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 13KB

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