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.

AbstractOrderedLayout.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. /*
  2. @VaadinApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.ui;
  5. import java.util.HashMap;
  6. import java.util.Iterator;
  7. import java.util.LinkedList;
  8. import java.util.Map;
  9. import com.vaadin.event.LayoutEvents.LayoutClickEvent;
  10. import com.vaadin.event.LayoutEvents.LayoutClickListener;
  11. import com.vaadin.event.LayoutEvents.LayoutClickNotifier;
  12. import com.vaadin.terminal.PaintException;
  13. import com.vaadin.terminal.PaintTarget;
  14. import com.vaadin.terminal.Sizeable;
  15. import com.vaadin.terminal.gwt.client.EventId;
  16. @SuppressWarnings("serial")
  17. public abstract class AbstractOrderedLayout extends AbstractLayout implements
  18. Layout.AlignmentHandler, Layout.SpacingHandler, LayoutClickNotifier {
  19. private static final String CLICK_EVENT = EventId.LAYOUT_CLICK;
  20. public static final Alignment ALIGNMENT_DEFAULT = Alignment.TOP_LEFT;
  21. /**
  22. * Custom layout slots containing the components.
  23. */
  24. protected LinkedList<Component> components = new LinkedList<Component>();
  25. /* Child component alignments */
  26. /**
  27. * Mapping from components to alignments (horizontal + vertical).
  28. */
  29. private final Map<Component, Alignment> componentToAlignment = new HashMap<Component, Alignment>();
  30. private final Map<Component, Float> componentToExpandRatio = new HashMap<Component, Float>();
  31. /**
  32. * Is spacing between contained components enabled. Defaults to false.
  33. */
  34. private boolean spacing = false;
  35. /**
  36. * Add a component into this container. The component is added to the right
  37. * or under the previous component.
  38. *
  39. * @param c
  40. * the component to be added.
  41. */
  42. @Override
  43. public void addComponent(Component c) {
  44. // Add to components before calling super.addComponent
  45. // so that it is available to AttachListeners
  46. components.add(c);
  47. try {
  48. super.addComponent(c);
  49. requestRepaint();
  50. } catch (IllegalArgumentException e) {
  51. components.remove(c);
  52. throw e;
  53. }
  54. }
  55. /**
  56. * Adds a component into this container. The component is added to the left
  57. * or on top of the other components.
  58. *
  59. * @param c
  60. * the component to be added.
  61. */
  62. public void addComponentAsFirst(Component c) {
  63. // If c is already in this, we must remove it before proceeding
  64. // see ticket #7668
  65. if (c.getParent() == this) {
  66. removeComponent(c);
  67. }
  68. components.addFirst(c);
  69. try {
  70. super.addComponent(c);
  71. requestRepaint();
  72. } catch (IllegalArgumentException e) {
  73. components.remove(c);
  74. throw e;
  75. }
  76. }
  77. /**
  78. * Adds a component into indexed position in this container.
  79. *
  80. * @param c
  81. * the component to be added.
  82. * @param index
  83. * the index of the component position. The components currently
  84. * in and after the position are shifted forwards.
  85. */
  86. public void addComponent(Component c, int index) {
  87. // If c is already in this, we must remove it before proceeding
  88. // see ticket #7668
  89. if (c.getParent() == this) {
  90. // When c is removed, all components after it are shifted down
  91. if (index > getComponentIndex(c)) {
  92. index--;
  93. }
  94. removeComponent(c);
  95. }
  96. components.add(index, c);
  97. try {
  98. super.addComponent(c);
  99. requestRepaint();
  100. } catch (IllegalArgumentException e) {
  101. components.remove(c);
  102. throw e;
  103. }
  104. }
  105. /**
  106. * Removes the component from this container.
  107. *
  108. * @param c
  109. * the component to be removed.
  110. */
  111. @Override
  112. public void removeComponent(Component c) {
  113. components.remove(c);
  114. componentToAlignment.remove(c);
  115. componentToExpandRatio.remove(c);
  116. super.removeComponent(c);
  117. requestRepaint();
  118. }
  119. /**
  120. * Gets the component container iterator for going trough all the components
  121. * in the container.
  122. *
  123. * @return the Iterator of the components inside the container.
  124. */
  125. public Iterator<Component> getComponentIterator() {
  126. return components.iterator();
  127. }
  128. /**
  129. * Gets the number of contained components. Consistent with the iterator
  130. * returned by {@link #getComponentIterator()}.
  131. *
  132. * @return the number of contained components
  133. */
  134. public int getComponentCount() {
  135. return components.size();
  136. }
  137. /**
  138. * Paints the content of this component.
  139. *
  140. * @param target
  141. * the Paint Event.
  142. * @throws PaintException
  143. * if the paint operation failed.
  144. */
  145. @Override
  146. public void paintContent(PaintTarget target) throws PaintException {
  147. super.paintContent(target);
  148. // Add spacing attribute (omitted if false)
  149. if (spacing) {
  150. target.addAttribute("spacing", spacing);
  151. }
  152. // Adds all items in all the locations
  153. for (Component c : components) {
  154. // Paint child component UIDL
  155. c.paint(target);
  156. }
  157. // Add child component alignment info to layout tag
  158. target.addAttribute("alignments", componentToAlignment);
  159. target.addAttribute("expandRatios", componentToExpandRatio);
  160. }
  161. /* Documented in superclass */
  162. public void replaceComponent(Component oldComponent, Component newComponent) {
  163. // Gets the locations
  164. int oldLocation = -1;
  165. int newLocation = -1;
  166. int location = 0;
  167. for (final Iterator<Component> i = components.iterator(); i.hasNext();) {
  168. final Component component = i.next();
  169. if (component == oldComponent) {
  170. oldLocation = location;
  171. }
  172. if (component == newComponent) {
  173. newLocation = location;
  174. }
  175. location++;
  176. }
  177. if (oldLocation == -1) {
  178. addComponent(newComponent);
  179. } else if (newLocation == -1) {
  180. removeComponent(oldComponent);
  181. addComponent(newComponent, oldLocation);
  182. } else {
  183. if (oldLocation > newLocation) {
  184. components.remove(oldComponent);
  185. components.add(newLocation, oldComponent);
  186. components.remove(newComponent);
  187. componentToAlignment.remove(newComponent);
  188. components.add(oldLocation, newComponent);
  189. } else {
  190. components.remove(newComponent);
  191. components.add(oldLocation, newComponent);
  192. components.remove(oldComponent);
  193. componentToAlignment.remove(oldComponent);
  194. components.add(newLocation, oldComponent);
  195. }
  196. requestRepaint();
  197. }
  198. }
  199. /*
  200. * (non-Javadoc)
  201. *
  202. * @see com.vaadin.ui.Layout.AlignmentHandler#setComponentAlignment(com
  203. * .vaadin.ui.Component, int, int)
  204. */
  205. public void setComponentAlignment(Component childComponent,
  206. int horizontalAlignment, int verticalAlignment) {
  207. if (components.contains(childComponent)) {
  208. // Alignments are bit masks
  209. componentToAlignment.put(childComponent, new Alignment(
  210. horizontalAlignment + verticalAlignment));
  211. requestRepaint();
  212. } else {
  213. throw new IllegalArgumentException(
  214. "Component must be added to layout before using setComponentAlignment()");
  215. }
  216. }
  217. public void setComponentAlignment(Component childComponent,
  218. Alignment alignment) {
  219. if (components.contains(childComponent)) {
  220. componentToAlignment.put(childComponent, alignment);
  221. requestRepaint();
  222. } else {
  223. throw new IllegalArgumentException(
  224. "Component must be added to layout before using setComponentAlignment()");
  225. }
  226. }
  227. /*
  228. * (non-Javadoc)
  229. *
  230. * @see com.vaadin.ui.Layout.AlignmentHandler#getComponentAlignment(com
  231. * .vaadin.ui.Component)
  232. */
  233. public Alignment getComponentAlignment(Component childComponent) {
  234. Alignment alignment = componentToAlignment.get(childComponent);
  235. if (alignment == null) {
  236. return ALIGNMENT_DEFAULT;
  237. } else {
  238. return alignment;
  239. }
  240. }
  241. /*
  242. * (non-Javadoc)
  243. *
  244. * @see com.vaadin.ui.Layout.SpacingHandler#setSpacing(boolean)
  245. */
  246. public void setSpacing(boolean enabled) {
  247. spacing = enabled;
  248. requestRepaint();
  249. }
  250. /*
  251. * (non-Javadoc)
  252. *
  253. * @see com.vaadin.ui.Layout.SpacingHandler#isSpacing()
  254. */
  255. @Deprecated
  256. public boolean isSpacingEnabled() {
  257. return spacing;
  258. }
  259. /*
  260. * (non-Javadoc)
  261. *
  262. * @see com.vaadin.ui.Layout.SpacingHandler#isSpacing()
  263. */
  264. public boolean isSpacing() {
  265. return spacing;
  266. }
  267. /**
  268. * <p>
  269. * This method is used to control how excess space in layout is distributed
  270. * among components. Excess space may exist if layout is sized and contained
  271. * non relatively sized components don't consume all available space.
  272. *
  273. * <p>
  274. * Example how to distribute 1:3 (33%) for component1 and 2:3 (67%) for
  275. * component2 :
  276. *
  277. * <code>
  278. * layout.setExpandRatio(component1, 1);<br>
  279. * layout.setExpandRatio(component2, 2);
  280. * </code>
  281. *
  282. * <p>
  283. * If no ratios have been set, the excess space is distributed evenly among
  284. * all components.
  285. *
  286. * <p>
  287. * Note, that width or height (depending on orientation) needs to be defined
  288. * for this method to have any effect.
  289. *
  290. * @see Sizeable
  291. *
  292. * @param component
  293. * the component in this layout which expand ratio is to be set
  294. * @param ratio
  295. */
  296. public void setExpandRatio(Component component, float ratio) {
  297. if (components.contains(component)) {
  298. componentToExpandRatio.put(component, ratio);
  299. requestRepaint();
  300. } else {
  301. throw new IllegalArgumentException(
  302. "Component must be added to layout before using setExpandRatio()");
  303. }
  304. };
  305. /**
  306. * Returns the expand ratio of given component.
  307. *
  308. * @param component
  309. * which expand ratios is requested
  310. * @return expand ratio of given component, 0.0f by default
  311. */
  312. public float getExpandRatio(Component component) {
  313. Float ratio = componentToExpandRatio.get(component);
  314. return (ratio == null) ? 0 : ratio.floatValue();
  315. }
  316. /**
  317. * Sets the component alignment using a short hand string notation.
  318. *
  319. * @deprecated Replaced by
  320. * {@link #setComponentAlignment(Component, Alignment)}
  321. *
  322. * @param component
  323. * A child component in this layout
  324. * @param alignment
  325. * A short hand notation described in {@link AlignmentUtils}
  326. */
  327. @Deprecated
  328. public void setComponentAlignment(Component component, String alignment) {
  329. AlignmentUtils.setComponentAlignment(this, component, alignment);
  330. }
  331. public void addListener(LayoutClickListener listener) {
  332. addListener(CLICK_EVENT, LayoutClickEvent.class, listener,
  333. LayoutClickListener.clickMethod);
  334. }
  335. public void removeListener(LayoutClickListener listener) {
  336. removeListener(CLICK_EVENT, LayoutClickEvent.class, listener);
  337. }
  338. /**
  339. * Returns the index of the given component.
  340. *
  341. * @param component
  342. * The component to look up.
  343. * @return The index of the component or -1 if the component is not a child.
  344. */
  345. public int getComponentIndex(Component component) {
  346. return components.indexOf(component);
  347. }
  348. /**
  349. * Returns the component at the given position.
  350. *
  351. * @param index
  352. * The position of the component.
  353. * @return The component at the given index.
  354. * @throws IndexOutOfBoundsException
  355. * If the index is out of range.
  356. */
  357. public Component getComponent(int index) throws IndexOutOfBoundsException {
  358. return components.get(index);
  359. }
  360. }