You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AbstractComponentContainer.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. /*
  2. * Copyright 2000-2018 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.ui;
  17. import java.util.Collection;
  18. import java.util.HashSet;
  19. import java.util.Iterator;
  20. import java.util.LinkedList;
  21. import com.vaadin.server.ComponentSizeValidator;
  22. import com.vaadin.shared.Registration;
  23. import com.vaadin.shared.ui.AbstractComponentContainerState;
  24. /**
  25. * Extension to {@link AbstractComponent} that defines the default
  26. * implementation for the methods in {@link ComponentContainer}. Basic UI
  27. * components that need to contain other components inherit this class to easily
  28. * qualify as a component container.
  29. *
  30. * @author Vaadin Ltd
  31. * @since 3.0
  32. */
  33. @SuppressWarnings("serial")
  34. public abstract class AbstractComponentContainer extends AbstractComponent
  35. implements ComponentContainer {
  36. /**
  37. * Constructs a new component container.
  38. */
  39. public AbstractComponentContainer() {
  40. super();
  41. }
  42. /*
  43. * (non-Javadoc)
  44. *
  45. * @see
  46. * com.vaadin.ui.ComponentContainer#addComponents(com.vaadin.ui.Component[])
  47. */
  48. @Override
  49. public void addComponents(Component... components) {
  50. for (Component c : components) {
  51. addComponent(c);
  52. }
  53. }
  54. /**
  55. * Removes all components from the container. This should probably be
  56. * re-implemented in extending classes for a more powerful implementation.
  57. */
  58. @Override
  59. public void removeAllComponents() {
  60. final LinkedList<Component> l = new LinkedList<>();
  61. // Adds all components
  62. for (final Iterator<Component> i = getComponentIterator(); i
  63. .hasNext();) {
  64. l.add(i.next());
  65. }
  66. // Removes all component
  67. for (Component aL : l) {
  68. removeComponent(aL);
  69. }
  70. }
  71. /*
  72. * Moves all components from an another container into this container. Don't
  73. * add a JavaDoc comment here, we use the default documentation from
  74. * implemented interface.
  75. */
  76. @Override
  77. public void moveComponentsFrom(ComponentContainer source) {
  78. final LinkedList<Component> components = new LinkedList<>();
  79. for (final Iterator<Component> i = source.getComponentIterator(); i
  80. .hasNext();) {
  81. components.add(i.next());
  82. }
  83. for (final Component c : components) {
  84. source.removeComponent(c);
  85. addComponent(c);
  86. }
  87. }
  88. /* documented in interface */
  89. @Override
  90. public Registration addComponentAttachListener(
  91. ComponentAttachListener listener) {
  92. return addListener(ComponentAttachEvent.class, listener,
  93. ComponentAttachListener.attachMethod);
  94. }
  95. /* documented in interface */
  96. @Override
  97. @Deprecated
  98. public void removeComponentAttachListener(
  99. ComponentAttachListener listener) {
  100. removeListener(ComponentAttachEvent.class, listener,
  101. ComponentAttachListener.attachMethod);
  102. }
  103. /* documented in interface */
  104. @Override
  105. public Registration addComponentDetachListener(
  106. ComponentDetachListener listener) {
  107. return addListener(ComponentDetachEvent.class, listener,
  108. ComponentDetachListener.detachMethod);
  109. }
  110. /* documented in interface */
  111. @Override
  112. @Deprecated
  113. public void removeComponentDetachListener(
  114. ComponentDetachListener listener) {
  115. removeListener(ComponentDetachEvent.class, listener,
  116. ComponentDetachListener.detachMethod);
  117. }
  118. /**
  119. * Fires the component attached event. This should be called by the
  120. * addComponent methods after the component have been added to this
  121. * container.
  122. *
  123. * @param component
  124. * the component that has been added to this container.
  125. */
  126. protected void fireComponentAttachEvent(Component component) {
  127. fireEvent(new ComponentAttachEvent(this, component));
  128. }
  129. /**
  130. * Fires the component detached event. This should be called by the
  131. * removeComponent methods after the component have been removed from this
  132. * container.
  133. *
  134. * @param component
  135. * the component that has been removed from this container.
  136. */
  137. protected void fireComponentDetachEvent(Component component) {
  138. fireEvent(new ComponentDetachEvent(this, component));
  139. }
  140. /**
  141. * This only implements the events and component parent calls. The extending
  142. * classes must implement component list maintenance and call this method
  143. * after component list maintenance.
  144. *
  145. * @see com.vaadin.ui.ComponentContainer#addComponent(Component)
  146. */
  147. @Override
  148. public void addComponent(Component c) {
  149. // Make sure we're not adding the component inside it's own content
  150. if (isOrHasAncestor(c)) {
  151. throw new IllegalArgumentException(
  152. "Component cannot be added inside it's own content");
  153. }
  154. if (c.getParent() != null) {
  155. // If the component already has a parent, try to remove it
  156. AbstractSingleComponentContainer.removeFromParent(c);
  157. }
  158. c.setParent(this);
  159. fireComponentAttachEvent(c);
  160. markAsDirty();
  161. }
  162. /**
  163. * This only implements the events and component parent calls. The extending
  164. * classes must implement component list maintenance and call this method
  165. * before component list maintenance.
  166. *
  167. * @see com.vaadin.ui.ComponentContainer#removeComponent(Component)
  168. */
  169. @Override
  170. public void removeComponent(Component c) {
  171. if (equals(c.getParent())) {
  172. c.setParent(null);
  173. fireComponentDetachEvent(c);
  174. markAsDirty();
  175. }
  176. }
  177. @Override
  178. public void setWidth(float width, Unit unit) {
  179. /*
  180. * child tree repaints may be needed, due to our fall back support for
  181. * invalid relative sizes
  182. */
  183. Collection<Component> dirtyChildren = null;
  184. boolean childrenMayBecomeUndefined = false;
  185. if (getWidth() == SIZE_UNDEFINED && width != SIZE_UNDEFINED) {
  186. // children currently in invalid state may need repaint
  187. dirtyChildren = getInvalidSizedChildren(false);
  188. } else if ((width == SIZE_UNDEFINED && getWidth() != SIZE_UNDEFINED)
  189. || (unit == Unit.PERCENTAGE
  190. && getWidthUnits() != Unit.PERCENTAGE
  191. && !ComponentSizeValidator
  192. .parentCanDefineWidth(this))) {
  193. /*
  194. * relative width children may get to invalid state if width becomes
  195. * invalid. Width may also become invalid if units become percentage
  196. * due to the fallback support
  197. */
  198. childrenMayBecomeUndefined = true;
  199. dirtyChildren = getInvalidSizedChildren(false);
  200. }
  201. super.setWidth(width, unit);
  202. repaintChangedChildTrees(dirtyChildren, childrenMayBecomeUndefined,
  203. false);
  204. }
  205. private void repaintChangedChildTrees(Collection<Component> invalidChildren,
  206. boolean childrenMayBecomeUndefined, boolean vertical) {
  207. if (childrenMayBecomeUndefined) {
  208. Collection<Component> previouslyInvalidComponents = invalidChildren;
  209. invalidChildren = getInvalidSizedChildren(vertical);
  210. if (previouslyInvalidComponents != null
  211. && invalidChildren != null) {
  212. for (Iterator<Component> iterator = invalidChildren
  213. .iterator(); iterator.hasNext();) {
  214. Component component = iterator.next();
  215. if (previouslyInvalidComponents.contains(component)) {
  216. // still invalid don't repaint
  217. iterator.remove();
  218. }
  219. }
  220. }
  221. } else if (invalidChildren != null) {
  222. Collection<Component> stillInvalidChildren = getInvalidSizedChildren(
  223. vertical);
  224. if (stillInvalidChildren != null) {
  225. for (Component component : stillInvalidChildren) {
  226. // didn't become valid
  227. invalidChildren.remove(component);
  228. }
  229. }
  230. }
  231. if (invalidChildren != null) {
  232. repaintChildTrees(invalidChildren);
  233. }
  234. }
  235. private Collection<Component> getInvalidSizedChildren(
  236. final boolean vertical) {
  237. HashSet<Component> components = null;
  238. for (Component component : this) {
  239. boolean valid = vertical
  240. ? ComponentSizeValidator.checkHeights(component)
  241. : ComponentSizeValidator.checkWidths(component);
  242. if (!valid) {
  243. if (components == null) {
  244. components = new HashSet<>();
  245. }
  246. components.add(component);
  247. }
  248. }
  249. return components;
  250. }
  251. private void repaintChildTrees(Collection<Component> dirtyChildren) {
  252. for (Component c : dirtyChildren) {
  253. c.markAsDirtyRecursive();
  254. }
  255. }
  256. @Override
  257. public void setHeight(float height, Unit unit) {
  258. /*
  259. * child tree repaints may be needed, due to our fall back support for
  260. * invalid relative sizes
  261. */
  262. Collection<Component> dirtyChildren = null;
  263. boolean childrenMayBecomeUndefined = false;
  264. if (getHeight() == SIZE_UNDEFINED && height != SIZE_UNDEFINED) {
  265. // children currently in invalid state may need repaint
  266. dirtyChildren = getInvalidSizedChildren(true);
  267. } else if ((height == SIZE_UNDEFINED && getHeight() != SIZE_UNDEFINED)
  268. || (unit == Unit.PERCENTAGE
  269. && getHeightUnits() != Unit.PERCENTAGE
  270. && !ComponentSizeValidator
  271. .parentCanDefineHeight(this))) {
  272. /*
  273. * relative height children may get to invalid state if height
  274. * becomes invalid. Height may also become invalid if units become
  275. * percentage due to the fallback support.
  276. */
  277. childrenMayBecomeUndefined = true;
  278. dirtyChildren = getInvalidSizedChildren(true);
  279. }
  280. super.setHeight(height, unit);
  281. repaintChangedChildTrees(dirtyChildren, childrenMayBecomeUndefined,
  282. true);
  283. }
  284. /**
  285. * {@inheritDoc}
  286. *
  287. * @deprecated As of 7.0, use {@link #iterator()} instead.
  288. */
  289. @Deprecated
  290. @Override
  291. public Iterator<Component> getComponentIterator() {
  292. return iterator();
  293. }
  294. @Override
  295. protected AbstractComponentContainerState getState() {
  296. return (AbstractComponentContainerState) super.getState();
  297. }
  298. @Override
  299. protected AbstractComponentContainerState getState(boolean markAsDirty) {
  300. return (AbstractComponentContainerState) super.getState(markAsDirty);
  301. }
  302. }