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

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