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.

ContainerHierarchicalWrapper.java 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  1. /*
  2. * Copyright 2000-2014 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.data.util;
  17. import java.io.Serializable;
  18. import java.util.Arrays;
  19. import java.util.Collection;
  20. import java.util.Collections;
  21. import java.util.Comparator;
  22. import java.util.HashSet;
  23. import java.util.Hashtable;
  24. import java.util.Iterator;
  25. import java.util.LinkedHashSet;
  26. import java.util.LinkedList;
  27. import com.vaadin.data.Container;
  28. import com.vaadin.data.Item;
  29. import com.vaadin.data.Property;
  30. /**
  31. * <p>
  32. * A wrapper class for adding external hierarchy to containers not implementing
  33. * the {@link com.vaadin.data.Container.Hierarchical} interface.
  34. * </p>
  35. *
  36. * <p>
  37. * If the wrapped container is changed directly (that is, not through the
  38. * wrapper), and does not implement Container.ItemSetChangeNotifier and/or
  39. * Container.PropertySetChangeNotifier the hierarchy information must be updated
  40. * with the {@link #updateHierarchicalWrapper()} method.
  41. * </p>
  42. *
  43. * @author Vaadin Ltd.
  44. * @since 3.0
  45. */
  46. @SuppressWarnings("serial")
  47. public class ContainerHierarchicalWrapper implements Container.Hierarchical,
  48. Container.ItemSetChangeNotifier, Container.PropertySetChangeNotifier {
  49. /** The wrapped container */
  50. private final Container container;
  51. /** Set of IDs of those contained Items that can't have children. */
  52. private HashSet<Object> noChildrenAllowed = null;
  53. /** Mapping from Item ID to parent Item ID */
  54. private Hashtable<Object, Object> parent = null;
  55. /** Mapping from Item ID to a list of child IDs */
  56. private Hashtable<Object, LinkedList<Object>> children = null;
  57. /** List that contains all root elements of the container. */
  58. private LinkedHashSet<Object> roots = null;
  59. /** Is the wrapped container hierarchical by itself ? */
  60. private boolean hierarchical;
  61. /**
  62. * A comparator that sorts the listed items before other items. Otherwise,
  63. * the order is undefined.
  64. */
  65. private static class ListedItemsFirstComparator implements
  66. Comparator<Object>, Serializable {
  67. private final Collection<?> itemIds;
  68. private ListedItemsFirstComparator(Collection<?> itemIds) {
  69. this.itemIds = itemIds;
  70. }
  71. @Override
  72. public int compare(Object o1, Object o2) {
  73. if (o1.equals(o2)) {
  74. return 0;
  75. }
  76. for (Object id : itemIds) {
  77. if (id == o1) {
  78. return -1;
  79. } else if (id == o2) {
  80. return 1;
  81. }
  82. }
  83. return 0;
  84. }
  85. }
  86. /**
  87. * Constructs a new hierarchical wrapper for an existing Container. Works
  88. * even if the to-be-wrapped container already implements the
  89. * <code>Container.Hierarchical</code> interface.
  90. *
  91. * @param toBeWrapped
  92. * the container that needs to be accessed hierarchically
  93. * @see #updateHierarchicalWrapper()
  94. */
  95. public ContainerHierarchicalWrapper(Container toBeWrapped) {
  96. container = toBeWrapped;
  97. hierarchical = container instanceof Container.Hierarchical;
  98. // Check arguments
  99. if (container == null) {
  100. throw new NullPointerException("Null can not be wrapped");
  101. }
  102. // Create initial order if needed
  103. if (!hierarchical) {
  104. noChildrenAllowed = new HashSet<Object>();
  105. parent = new Hashtable<Object, Object>();
  106. children = new Hashtable<Object, LinkedList<Object>>();
  107. roots = new LinkedHashSet<Object>(container.getItemIds());
  108. }
  109. updateHierarchicalWrapper();
  110. }
  111. /**
  112. * Updates the wrapper's internal hierarchy data to include all Items in the
  113. * underlying container. If the contents of the wrapped container change
  114. * without the wrapper's knowledge, this method needs to be called to update
  115. * the hierarchy information of the Items.
  116. */
  117. public void updateHierarchicalWrapper() {
  118. if (!hierarchical) {
  119. // Recreate hierarchy and data structures if missing
  120. if (noChildrenAllowed == null || parent == null || children == null
  121. || roots == null) {
  122. noChildrenAllowed = new HashSet<Object>();
  123. parent = new Hashtable<Object, Object>();
  124. children = new Hashtable<Object, LinkedList<Object>>();
  125. roots = new LinkedHashSet<Object>(container.getItemIds());
  126. }
  127. // Check that the hierarchy is up-to-date
  128. else {
  129. // ensure order of root and child lists is same as in wrapped
  130. // container
  131. Collection<?> itemIds = container.getItemIds();
  132. Comparator<Object> basedOnOrderFromWrappedContainer = new ListedItemsFirstComparator(
  133. itemIds);
  134. // Calculate the set of all items in the hierarchy
  135. final HashSet<Object> s = new HashSet<Object>();
  136. s.addAll(parent.keySet());
  137. s.addAll(children.keySet());
  138. s.addAll(roots);
  139. // Remove unnecessary items
  140. for (final Iterator<Object> i = s.iterator(); i.hasNext();) {
  141. final Object id = i.next();
  142. if (!container.containsId(id)) {
  143. removeFromHierarchyWrapper(id);
  144. }
  145. }
  146. // Add all the missing items
  147. final Collection<?> ids = container.getItemIds();
  148. for (final Iterator<?> i = ids.iterator(); i.hasNext();) {
  149. final Object id = i.next();
  150. if (!s.contains(id)) {
  151. addToHierarchyWrapper(id);
  152. s.add(id);
  153. }
  154. }
  155. Object[] array = roots.toArray();
  156. Arrays.sort(array, basedOnOrderFromWrappedContainer);
  157. roots = new LinkedHashSet<Object>();
  158. for (int i = 0; i < array.length; i++) {
  159. roots.add(array[i]);
  160. }
  161. for (Object object : children.keySet()) {
  162. LinkedList<Object> object2 = children.get(object);
  163. Collections.sort(object2, basedOnOrderFromWrappedContainer);
  164. }
  165. }
  166. }
  167. }
  168. /**
  169. * Removes the specified Item from the wrapper's internal hierarchy
  170. * structure.
  171. * <p>
  172. * Note : The Item is not removed from the underlying Container.
  173. * </p>
  174. *
  175. * @param itemId
  176. * the ID of the item to remove from the hierarchy.
  177. */
  178. private void removeFromHierarchyWrapper(Object itemId) {
  179. LinkedList<Object> oprhanedChildren = children.remove(itemId);
  180. if (oprhanedChildren != null) {
  181. for (Object object : oprhanedChildren) {
  182. // make orphaned children root nodes
  183. setParent(object, null);
  184. }
  185. }
  186. roots.remove(itemId);
  187. final Object p = parent.get(itemId);
  188. if (p != null) {
  189. final LinkedList<Object> c = children.get(p);
  190. if (c != null) {
  191. c.remove(itemId);
  192. }
  193. }
  194. parent.remove(itemId);
  195. noChildrenAllowed.remove(itemId);
  196. }
  197. /**
  198. * Adds the specified Item specified to the internal hierarchy structure.
  199. * The new item is added as a root Item. The underlying container is not
  200. * modified.
  201. *
  202. * @param itemId
  203. * the ID of the item to add to the hierarchy.
  204. */
  205. private void addToHierarchyWrapper(Object itemId) {
  206. roots.add(itemId);
  207. }
  208. /*
  209. * Can the specified Item have any children? Don't add a JavaDoc comment
  210. * here, we use the default documentation from implemented interface.
  211. */
  212. @Override
  213. public boolean areChildrenAllowed(Object itemId) {
  214. // If the wrapped container implements the method directly, use it
  215. if (hierarchical) {
  216. return ((Container.Hierarchical) container)
  217. .areChildrenAllowed(itemId);
  218. }
  219. if (noChildrenAllowed.contains(itemId)) {
  220. return false;
  221. }
  222. return containsId(itemId);
  223. }
  224. /*
  225. * Gets the IDs of the children of the specified Item. Don't add a JavaDoc
  226. * comment here, we use the default documentation from implemented
  227. * interface.
  228. */
  229. @Override
  230. public Collection<?> getChildren(Object itemId) {
  231. // If the wrapped container implements the method directly, use it
  232. if (hierarchical) {
  233. return ((Container.Hierarchical) container).getChildren(itemId);
  234. }
  235. final Collection<?> c = children.get(itemId);
  236. if (c == null) {
  237. return null;
  238. }
  239. return Collections.unmodifiableCollection(c);
  240. }
  241. /*
  242. * Gets the ID of the parent of the specified Item. Don't add a JavaDoc
  243. * comment here, we use the default documentation from implemented
  244. * interface.
  245. */
  246. @Override
  247. public Object getParent(Object itemId) {
  248. // If the wrapped container implements the method directly, use it
  249. if (hierarchical) {
  250. return ((Container.Hierarchical) container).getParent(itemId);
  251. }
  252. return parent.get(itemId);
  253. }
  254. /*
  255. * Is the Item corresponding to the given ID a leaf node? Don't add a
  256. * JavaDoc comment here, we use the default documentation from implemented
  257. * interface.
  258. */
  259. @Override
  260. public boolean hasChildren(Object itemId) {
  261. // If the wrapped container implements the method directly, use it
  262. if (hierarchical) {
  263. return ((Container.Hierarchical) container).hasChildren(itemId);
  264. }
  265. LinkedList<Object> list = children.get(itemId);
  266. return (list != null && !list.isEmpty());
  267. }
  268. /*
  269. * Is the Item corresponding to the given ID a root node? Don't add a
  270. * JavaDoc comment here, we use the default documentation from implemented
  271. * interface.
  272. */
  273. @Override
  274. public boolean isRoot(Object itemId) {
  275. // If the wrapped container implements the method directly, use it
  276. if (hierarchical) {
  277. return ((Container.Hierarchical) container).isRoot(itemId);
  278. }
  279. if (parent.containsKey(itemId)) {
  280. return false;
  281. }
  282. return containsId(itemId);
  283. }
  284. /*
  285. * Gets the IDs of the root elements in the container. Don't add a JavaDoc
  286. * comment here, we use the default documentation from implemented
  287. * interface.
  288. */
  289. @Override
  290. public Collection<?> rootItemIds() {
  291. // If the wrapped container implements the method directly, use it
  292. if (hierarchical) {
  293. return ((Container.Hierarchical) container).rootItemIds();
  294. }
  295. return Collections.unmodifiableCollection(roots);
  296. }
  297. /**
  298. * <p>
  299. * Sets the given Item's capability to have children. If the Item identified
  300. * with the itemId already has children and the areChildrenAllowed is false
  301. * this method fails and <code>false</code> is returned; the children must
  302. * be first explicitly removed with
  303. * {@link #setParent(Object itemId, Object newParentId)} or
  304. * {@link com.vaadin.data.Container#removeItem(Object itemId)}.
  305. * </p>
  306. *
  307. * @param itemId
  308. * the ID of the Item in the container whose child capability is
  309. * to be set.
  310. * @param childrenAllowed
  311. * the boolean value specifying if the Item can have children or
  312. * not.
  313. * @return <code>true</code> if the operation succeeded, <code>false</code>
  314. * if not
  315. */
  316. @Override
  317. public boolean setChildrenAllowed(Object itemId, boolean childrenAllowed) {
  318. // If the wrapped container implements the method directly, use it
  319. if (hierarchical) {
  320. return ((Container.Hierarchical) container).setChildrenAllowed(
  321. itemId, childrenAllowed);
  322. }
  323. // Check that the item is in the container
  324. if (!containsId(itemId)) {
  325. return false;
  326. }
  327. // Update status
  328. if (childrenAllowed) {
  329. noChildrenAllowed.remove(itemId);
  330. } else {
  331. noChildrenAllowed.add(itemId);
  332. }
  333. return true;
  334. }
  335. /**
  336. * <p>
  337. * Sets the parent of an Item. The new parent item must exist and be able to
  338. * have children. (<code>canHaveChildren(newParentId) == true</code>). It is
  339. * also possible to detach a node from the hierarchy (and thus make it root)
  340. * by setting the parent <code>null</code>.
  341. * </p>
  342. *
  343. * @param itemId
  344. * the ID of the item to be set as the child of the Item
  345. * identified with newParentId.
  346. * @param newParentId
  347. * the ID of the Item that's to be the new parent of the Item
  348. * identified with itemId.
  349. * @return <code>true</code> if the operation succeeded, <code>false</code>
  350. * if not
  351. */
  352. @Override
  353. public boolean setParent(Object itemId, Object newParentId) {
  354. // If the wrapped container implements the method directly, use it
  355. if (hierarchical) {
  356. return ((Container.Hierarchical) container).setParent(itemId,
  357. newParentId);
  358. }
  359. // Check that the item is in the container
  360. if (!containsId(itemId)) {
  361. return false;
  362. }
  363. // Get the old parent
  364. final Object oldParentId = parent.get(itemId);
  365. // Check if no change is necessary
  366. if ((newParentId == null && oldParentId == null)
  367. || (newParentId != null && newParentId.equals(oldParentId))) {
  368. return true;
  369. }
  370. // Making root
  371. if (newParentId == null) {
  372. // Remove from old parents children list
  373. final LinkedList<Object> l = children.get(oldParentId);
  374. if (l != null) {
  375. l.remove(itemId);
  376. if (l.isEmpty()) {
  377. children.remove(itemId);
  378. }
  379. }
  380. // Add to be a root
  381. roots.add(itemId);
  382. // Update parent
  383. parent.remove(itemId);
  384. fireItemSetChangeIfAbstractContainer();
  385. return true;
  386. }
  387. // Check that the new parent exists in container and can have
  388. // children
  389. if (!containsId(newParentId) || noChildrenAllowed.contains(newParentId)) {
  390. return false;
  391. }
  392. // Check that setting parent doesn't result to a loop
  393. Object o = newParentId;
  394. while (o != null && !o.equals(itemId)) {
  395. o = parent.get(o);
  396. }
  397. if (o != null) {
  398. return false;
  399. }
  400. // Update parent
  401. parent.put(itemId, newParentId);
  402. LinkedList<Object> pcl = children.get(newParentId);
  403. if (pcl == null) {
  404. pcl = new LinkedList<Object>();
  405. children.put(newParentId, pcl);
  406. }
  407. pcl.add(itemId);
  408. // Remove from old parent or root
  409. if (oldParentId == null) {
  410. roots.remove(itemId);
  411. } else {
  412. final LinkedList<Object> l = children.get(oldParentId);
  413. if (l != null) {
  414. l.remove(itemId);
  415. if (l.isEmpty()) {
  416. children.remove(oldParentId);
  417. }
  418. }
  419. }
  420. fireItemSetChangeIfAbstractContainer();
  421. return true;
  422. }
  423. /**
  424. * inform container (if it is instance of AbstractContainer) about the
  425. * change in hierarchy (#15421)
  426. */
  427. private void fireItemSetChangeIfAbstractContainer() {
  428. if (container instanceof AbstractContainer) {
  429. ((AbstractContainer) container).fireItemSetChange();
  430. }
  431. }
  432. /**
  433. * Creates a new Item into the Container, assigns it an automatic ID, and
  434. * adds it to the hierarchy.
  435. *
  436. * @return the autogenerated ID of the new Item or <code>null</code> if the
  437. * operation failed
  438. * @throws UnsupportedOperationException
  439. * if the addItem is not supported.
  440. */
  441. @Override
  442. public Object addItem() throws UnsupportedOperationException {
  443. final Object id = container.addItem();
  444. if (!hierarchical && id != null) {
  445. addToHierarchyWrapper(id);
  446. }
  447. return id;
  448. }
  449. /**
  450. * Adds a new Item by its ID to the underlying container and to the
  451. * hierarchy.
  452. *
  453. * @param itemId
  454. * the ID of the Item to be created.
  455. * @return the added Item or <code>null</code> if the operation failed.
  456. * @throws UnsupportedOperationException
  457. * if the addItem is not supported.
  458. */
  459. @Override
  460. public Item addItem(Object itemId) throws UnsupportedOperationException {
  461. // Null ids are not accepted
  462. if (itemId == null) {
  463. throw new NullPointerException("Container item id can not be null");
  464. }
  465. final Item item = container.addItem(itemId);
  466. if (!hierarchical && item != null) {
  467. addToHierarchyWrapper(itemId);
  468. }
  469. return item;
  470. }
  471. /**
  472. * Removes all items from the underlying container and from the hierarcy.
  473. *
  474. * @return <code>true</code> if the operation succeeded, <code>false</code>
  475. * if not
  476. * @throws UnsupportedOperationException
  477. * if the removeAllItems is not supported.
  478. */
  479. @Override
  480. public boolean removeAllItems() throws UnsupportedOperationException {
  481. final boolean success = container.removeAllItems();
  482. if (!hierarchical && success) {
  483. roots.clear();
  484. parent.clear();
  485. children.clear();
  486. noChildrenAllowed.clear();
  487. }
  488. return success;
  489. }
  490. /**
  491. * Removes an Item specified by the itemId from the underlying container and
  492. * from the hierarchy.
  493. *
  494. * @param itemId
  495. * the ID of the Item to be removed.
  496. * @return <code>true</code> if the operation succeeded, <code>false</code>
  497. * if not
  498. * @throws UnsupportedOperationException
  499. * if the removeItem is not supported.
  500. */
  501. @Override
  502. public boolean removeItem(Object itemId)
  503. throws UnsupportedOperationException {
  504. final boolean success = container.removeItem(itemId);
  505. if (!hierarchical && success) {
  506. removeFromHierarchyWrapper(itemId);
  507. }
  508. return success;
  509. }
  510. /**
  511. * Removes the Item identified by given itemId and all its children.
  512. *
  513. * @see #removeItem(Object)
  514. * @param itemId
  515. * the identifier of the Item to be removed
  516. * @return true if the operation succeeded
  517. */
  518. public boolean removeItemRecursively(Object itemId) {
  519. return HierarchicalContainer.removeItemRecursively(this, itemId);
  520. }
  521. /**
  522. * Adds a new Property to all Items in the Container.
  523. *
  524. * @param propertyId
  525. * the ID of the new Property.
  526. * @param type
  527. * the Data type of the new Property.
  528. * @param defaultValue
  529. * the value all created Properties are initialized to.
  530. * @return <code>true</code> if the operation succeeded, <code>false</code>
  531. * if not
  532. * @throws UnsupportedOperationException
  533. * if the addContainerProperty is not supported.
  534. */
  535. @Override
  536. public boolean addContainerProperty(Object propertyId, Class<?> type,
  537. Object defaultValue) throws UnsupportedOperationException {
  538. return container.addContainerProperty(propertyId, type, defaultValue);
  539. }
  540. /**
  541. * Removes the specified Property from the underlying container and from the
  542. * hierarchy.
  543. * <p>
  544. * Note : The Property will be removed from all Items in the Container.
  545. * </p>
  546. *
  547. * @param propertyId
  548. * the ID of the Property to remove.
  549. * @return <code>true</code> if the operation succeeded, <code>false</code>
  550. * if not
  551. * @throws UnsupportedOperationException
  552. * if the removeContainerProperty is not supported.
  553. */
  554. @Override
  555. public boolean removeContainerProperty(Object propertyId)
  556. throws UnsupportedOperationException {
  557. return container.removeContainerProperty(propertyId);
  558. }
  559. /*
  560. * Does the container contain the specified Item? Don't add a JavaDoc
  561. * comment here, we use the default documentation from implemented
  562. * interface.
  563. */
  564. @Override
  565. public boolean containsId(Object itemId) {
  566. return container.containsId(itemId);
  567. }
  568. /*
  569. * Gets the specified Item from the container. Don't add a JavaDoc comment
  570. * here, we use the default documentation from implemented interface.
  571. */
  572. @Override
  573. public Item getItem(Object itemId) {
  574. return container.getItem(itemId);
  575. }
  576. /*
  577. * Gets the ID's of all Items stored in the Container Don't add a JavaDoc
  578. * comment here, we use the default documentation from implemented
  579. * interface.
  580. */
  581. @Override
  582. public Collection<?> getItemIds() {
  583. return container.getItemIds();
  584. }
  585. /*
  586. * Gets the Property identified by the given itemId and propertyId from the
  587. * Container Don't add a JavaDoc comment here, we use the default
  588. * documentation from implemented interface.
  589. */
  590. @Override
  591. public Property getContainerProperty(Object itemId, Object propertyId) {
  592. return container.getContainerProperty(itemId, propertyId);
  593. }
  594. /*
  595. * Gets the ID's of all Properties stored in the Container Don't add a
  596. * JavaDoc comment here, we use the default documentation from implemented
  597. * interface.
  598. */
  599. @Override
  600. public Collection<?> getContainerPropertyIds() {
  601. return container.getContainerPropertyIds();
  602. }
  603. /*
  604. * Gets the data type of all Properties identified by the given Property ID.
  605. * Don't add a JavaDoc comment here, we use the default documentation from
  606. * implemented interface.
  607. */
  608. @Override
  609. public Class<?> getType(Object propertyId) {
  610. return container.getType(propertyId);
  611. }
  612. /*
  613. * Gets the number of Items in the Container. Don't add a JavaDoc comment
  614. * here, we use the default documentation from implemented interface.
  615. */
  616. @Override
  617. public int size() {
  618. int size = container.size();
  619. assert size >= 0;
  620. return size;
  621. }
  622. /*
  623. * Registers a new Item set change listener for this Container. Don't add a
  624. * JavaDoc comment here, we use the default documentation from implemented
  625. * interface.
  626. */
  627. @Override
  628. public void addItemSetChangeListener(
  629. Container.ItemSetChangeListener listener) {
  630. if (container instanceof Container.ItemSetChangeNotifier) {
  631. ((Container.ItemSetChangeNotifier) container)
  632. .addItemSetChangeListener(new PiggybackListener(listener));
  633. }
  634. }
  635. /**
  636. * @deprecated As of 7.0, replaced by
  637. * {@link #addItemSetChangeListener(com.vaadin.data.Container.ItemSetChangeListener)}
  638. **/
  639. @Override
  640. @Deprecated
  641. public void addListener(Container.ItemSetChangeListener listener) {
  642. addItemSetChangeListener(listener);
  643. }
  644. /*
  645. * Removes a Item set change listener from the object. Don't add a JavaDoc
  646. * comment here, we use the default documentation from implemented
  647. * interface.
  648. */
  649. @Override
  650. public void removeItemSetChangeListener(
  651. Container.ItemSetChangeListener listener) {
  652. if (container instanceof Container.ItemSetChangeNotifier) {
  653. ((Container.ItemSetChangeNotifier) container)
  654. .removeItemSetChangeListener(new PiggybackListener(listener));
  655. }
  656. }
  657. /**
  658. * @deprecated As of 7.0, replaced by
  659. * {@link #removeItemSetChangeListener(com.vaadin.data.Container.ItemSetChangeListener)}
  660. **/
  661. @Override
  662. @Deprecated
  663. public void removeListener(Container.ItemSetChangeListener listener) {
  664. removeItemSetChangeListener(listener);
  665. }
  666. /*
  667. * Registers a new Property set change listener for this Container. Don't
  668. * add a JavaDoc comment here, we use the default documentation from
  669. * implemented interface.
  670. */
  671. @Override
  672. public void addPropertySetChangeListener(
  673. Container.PropertySetChangeListener listener) {
  674. if (container instanceof Container.PropertySetChangeNotifier) {
  675. ((Container.PropertySetChangeNotifier) container)
  676. .addPropertySetChangeListener(new PiggybackListener(
  677. listener));
  678. }
  679. }
  680. /**
  681. * @deprecated As of 7.0, replaced by
  682. * {@link #addPropertySetChangeListener(com.vaadin.data.Container.PropertySetChangeListener)}
  683. **/
  684. @Override
  685. @Deprecated
  686. public void addListener(Container.PropertySetChangeListener listener) {
  687. addPropertySetChangeListener(listener);
  688. }
  689. /*
  690. * Removes a Property set change listener from the object. Don't add a
  691. * JavaDoc comment here, we use the default documentation from implemented
  692. * interface.
  693. */
  694. @Override
  695. public void removePropertySetChangeListener(
  696. Container.PropertySetChangeListener listener) {
  697. if (container instanceof Container.PropertySetChangeNotifier) {
  698. ((Container.PropertySetChangeNotifier) container)
  699. .removePropertySetChangeListener(new PiggybackListener(
  700. listener));
  701. }
  702. }
  703. /**
  704. * @deprecated As of 7.0, replaced by
  705. * {@link #removePropertySetChangeListener(com.vaadin.data.Container.PropertySetChangeListener)}
  706. **/
  707. @Override
  708. @Deprecated
  709. public void removeListener(Container.PropertySetChangeListener listener) {
  710. removePropertySetChangeListener(listener);
  711. }
  712. /**
  713. * This listener 'piggybacks' on the real listener in order to update the
  714. * wrapper when needed. It proxies equals() and hashCode() to the real
  715. * listener so that the correct listener gets removed.
  716. *
  717. */
  718. private class PiggybackListener implements
  719. Container.PropertySetChangeListener,
  720. Container.ItemSetChangeListener {
  721. Object listener;
  722. public PiggybackListener(Object realListener) {
  723. listener = realListener;
  724. }
  725. @Override
  726. public void containerItemSetChange(ItemSetChangeEvent event) {
  727. updateHierarchicalWrapper();
  728. ((Container.ItemSetChangeListener) listener)
  729. .containerItemSetChange(event);
  730. }
  731. @Override
  732. public void containerPropertySetChange(PropertySetChangeEvent event) {
  733. updateHierarchicalWrapper();
  734. ((Container.PropertySetChangeListener) listener)
  735. .containerPropertySetChange(event);
  736. }
  737. @Override
  738. public boolean equals(Object obj) {
  739. return obj == listener || (obj != null && obj.equals(listener));
  740. }
  741. @Override
  742. public int hashCode() {
  743. return listener.hashCode();
  744. }
  745. }
  746. }