選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

HierarchicalContainer.java 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806
  1. /*
  2. @VaadinApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.data.util;
  5. import java.util.Collection;
  6. import java.util.Collections;
  7. import java.util.HashMap;
  8. import java.util.HashSet;
  9. import java.util.LinkedHashSet;
  10. import java.util.LinkedList;
  11. import java.util.Set;
  12. import com.vaadin.data.Container;
  13. import com.vaadin.data.Item;
  14. /**
  15. * A specialized Container whose contents can be accessed like it was a
  16. * tree-like structure.
  17. *
  18. * @author Vaadin Ltd.
  19. * @version
  20. * @VERSION@
  21. * @since 3.0
  22. */
  23. @SuppressWarnings("serial")
  24. public class HierarchicalContainer extends IndexedContainer implements
  25. Container.Hierarchical {
  26. /**
  27. * Set of IDs of those contained Items that can't have children.
  28. */
  29. private final HashSet<Object> noChildrenAllowed = new HashSet<Object>();
  30. /**
  31. * Mapping from Item ID to parent Item ID.
  32. */
  33. private final HashMap<Object, Object> parent = new HashMap<Object, Object>();
  34. /**
  35. * Mapping from Item ID to parent Item ID for items included in the filtered
  36. * container.
  37. */
  38. private HashMap<Object, Object> filteredParent = null;
  39. /**
  40. * Mapping from Item ID to a list of child IDs.
  41. */
  42. private final HashMap<Object, LinkedList<Object>> children = new HashMap<Object, LinkedList<Object>>();
  43. /**
  44. * Mapping from Item ID to a list of child IDs when filtered
  45. */
  46. private HashMap<Object, LinkedList<Object>> filteredChildren = null;
  47. /**
  48. * List that contains all root elements of the container.
  49. */
  50. private final LinkedList<Object> roots = new LinkedList<Object>();
  51. /**
  52. * List that contains all filtered root elements of the container.
  53. */
  54. private LinkedList<Object> filteredRoots = null;
  55. /**
  56. * Determines how filtering of the container is done.
  57. */
  58. private boolean includeParentsWhenFiltering = true;
  59. private boolean contentChangedEventsDisabled = false;
  60. private boolean contentsChangedEventPending;
  61. /*
  62. * Can the specified Item have any children? Don't add a JavaDoc comment
  63. * here, we use the default documentation from implemented interface.
  64. */
  65. public boolean areChildrenAllowed(Object itemId) {
  66. if (noChildrenAllowed.contains(itemId)) {
  67. return false;
  68. }
  69. return containsId(itemId);
  70. }
  71. /*
  72. * Gets the IDs of the children of the specified Item. Don't add a JavaDoc
  73. * comment here, we use the default documentation from implemented
  74. * interface.
  75. */
  76. public Collection<?> getChildren(Object itemId) {
  77. LinkedList<Object> c;
  78. if (filteredChildren != null) {
  79. c = filteredChildren.get(itemId);
  80. } else {
  81. c = children.get(itemId);
  82. }
  83. if (c == null) {
  84. return null;
  85. }
  86. return Collections.unmodifiableCollection(c);
  87. }
  88. /*
  89. * Gets the ID of the parent of the specified Item. Don't add a JavaDoc
  90. * comment here, we use the default documentation from implemented
  91. * interface.
  92. */
  93. public Object getParent(Object itemId) {
  94. if (filteredParent != null) {
  95. return filteredParent.get(itemId);
  96. }
  97. return parent.get(itemId);
  98. }
  99. /*
  100. * Is the Item corresponding to the given ID a leaf node? Don't add a
  101. * JavaDoc comment here, we use the default documentation from implemented
  102. * interface.
  103. */
  104. public boolean hasChildren(Object itemId) {
  105. if (filteredChildren != null) {
  106. return filteredChildren.containsKey(itemId);
  107. } else {
  108. return children.containsKey(itemId);
  109. }
  110. }
  111. /*
  112. * Is the Item corresponding to the given ID a root node? Don't add a
  113. * JavaDoc comment here, we use the default documentation from implemented
  114. * interface.
  115. */
  116. public boolean isRoot(Object itemId) {
  117. // If the container is filtered the itemId must be among filteredRoots
  118. // to be a root.
  119. if (filteredRoots != null) {
  120. if (!filteredRoots.contains(itemId)) {
  121. return false;
  122. }
  123. } else {
  124. // Container is not filtered
  125. if (parent.containsKey(itemId)) {
  126. return false;
  127. }
  128. }
  129. return containsId(itemId);
  130. }
  131. /*
  132. * Gets the IDs of the root elements in the container. Don't add a JavaDoc
  133. * comment here, we use the default documentation from implemented
  134. * interface.
  135. */
  136. public Collection<?> rootItemIds() {
  137. if (filteredRoots != null) {
  138. return Collections.unmodifiableCollection(filteredRoots);
  139. } else {
  140. return Collections.unmodifiableCollection(roots);
  141. }
  142. }
  143. /**
  144. * <p>
  145. * Sets the given Item's capability to have children. If the Item identified
  146. * with the itemId already has children and the areChildrenAllowed is false
  147. * this method fails and <code>false</code> is returned; the children must
  148. * be first explicitly removed with
  149. * {@link #setParent(Object itemId, Object newParentId)} or
  150. * {@link com.vaadin.data.Container#removeItem(Object itemId)}.
  151. * </p>
  152. *
  153. * @param itemId
  154. * the ID of the Item in the container whose child capability is
  155. * to be set.
  156. * @param childrenAllowed
  157. * the boolean value specifying if the Item can have children or
  158. * not.
  159. * @return <code>true</code> if the operation succeeded, <code>false</code>
  160. * if not
  161. */
  162. public boolean setChildrenAllowed(Object itemId, boolean childrenAllowed) {
  163. // Checks that the item is in the container
  164. if (!containsId(itemId)) {
  165. return false;
  166. }
  167. // Updates status
  168. if (childrenAllowed) {
  169. noChildrenAllowed.remove(itemId);
  170. } else {
  171. noChildrenAllowed.add(itemId);
  172. }
  173. return true;
  174. }
  175. /**
  176. * <p>
  177. * Sets the parent of an Item. The new parent item must exist and be able to
  178. * have children. (<code>canHaveChildren(newParentId) == true</code>). It is
  179. * also possible to detach a node from the hierarchy (and thus make it root)
  180. * by setting the parent <code>null</code>.
  181. * </p>
  182. *
  183. * @param itemId
  184. * the ID of the item to be set as the child of the Item
  185. * identified with newParentId.
  186. * @param newParentId
  187. * the ID of the Item that's to be the new parent of the Item
  188. * identified with itemId.
  189. * @return <code>true</code> if the operation succeeded, <code>false</code>
  190. * if not
  191. */
  192. public boolean setParent(Object itemId, Object newParentId) {
  193. // Checks that the item is in the container
  194. if (!containsId(itemId)) {
  195. return false;
  196. }
  197. // Gets the old parent
  198. final Object oldParentId = parent.get(itemId);
  199. // Checks if no change is necessary
  200. if ((newParentId == null && oldParentId == null)
  201. || ((newParentId != null) && newParentId.equals(oldParentId))) {
  202. return true;
  203. }
  204. // Making root?
  205. if (newParentId == null) {
  206. // The itemId should become a root so we need to
  207. // - Remove it from the old parent's children list
  208. // - Add it as a root
  209. // - Remove it from the item -> parent list (parent is null for
  210. // roots)
  211. // Removes from old parents children list
  212. final LinkedList<Object> l = children.get(oldParentId);
  213. if (l != null) {
  214. l.remove(itemId);
  215. if (l.isEmpty()) {
  216. children.remove(oldParentId);
  217. }
  218. }
  219. // Add to be a root
  220. roots.add(itemId);
  221. // Updates parent
  222. parent.remove(itemId);
  223. if (hasFilters()) {
  224. // Refilter the container if setParent is called when filters
  225. // are applied. Changing parent can change what is included in
  226. // the filtered version (if includeParentsWhenFiltering==true).
  227. doFilterContainer(hasFilters());
  228. }
  229. fireItemSetChange();
  230. return true;
  231. }
  232. // We get here when the item should not become a root and we need to
  233. // - Verify the new parent exists and can have children
  234. // - Check that the new parent is not a child of the selected itemId
  235. // - Updated the item -> parent mapping to point to the new parent
  236. // - Remove the item from the roots list if it was a root
  237. // - Remove the item from the old parent's children list if it was not a
  238. // root
  239. // Checks that the new parent exists in container and can have
  240. // children
  241. if (!containsId(newParentId) || noChildrenAllowed.contains(newParentId)) {
  242. return false;
  243. }
  244. // Checks that setting parent doesn't result to a loop
  245. Object o = newParentId;
  246. while (o != null && !o.equals(itemId)) {
  247. o = parent.get(o);
  248. }
  249. if (o != null) {
  250. return false;
  251. }
  252. // Updates parent
  253. parent.put(itemId, newParentId);
  254. LinkedList<Object> pcl = children.get(newParentId);
  255. if (pcl == null) {
  256. // Create an empty list for holding children if one were not
  257. // previously created
  258. pcl = new LinkedList<Object>();
  259. children.put(newParentId, pcl);
  260. }
  261. pcl.add(itemId);
  262. // Removes from old parent or root
  263. if (oldParentId == null) {
  264. roots.remove(itemId);
  265. } else {
  266. final LinkedList<Object> l = children.get(oldParentId);
  267. if (l != null) {
  268. l.remove(itemId);
  269. if (l.isEmpty()) {
  270. children.remove(oldParentId);
  271. }
  272. }
  273. }
  274. if (hasFilters()) {
  275. // Refilter the container if setParent is called when filters
  276. // are applied. Changing parent can change what is included in
  277. // the filtered version (if includeParentsWhenFiltering==true).
  278. doFilterContainer(hasFilters());
  279. }
  280. fireItemSetChange();
  281. return true;
  282. }
  283. private boolean hasFilters() {
  284. return (filteredRoots != null);
  285. }
  286. /**
  287. * Moves a node (an Item) in the container immediately after a sibling node.
  288. * The two nodes must have the same parent in the container.
  289. *
  290. * @param itemId
  291. * the identifier of the moved node (Item)
  292. * @param siblingId
  293. * the identifier of the reference node (Item), after which the
  294. * other node will be located
  295. */
  296. public void moveAfterSibling(Object itemId, Object siblingId) {
  297. Object parent2 = getParent(itemId);
  298. LinkedList<Object> childrenList;
  299. if (parent2 == null) {
  300. childrenList = roots;
  301. } else {
  302. childrenList = children.get(parent2);
  303. }
  304. if (siblingId == null) {
  305. childrenList.remove(itemId);
  306. childrenList.addFirst(itemId);
  307. } else {
  308. int oldIndex = childrenList.indexOf(itemId);
  309. int indexOfSibling = childrenList.indexOf(siblingId);
  310. if (indexOfSibling != -1 && oldIndex != -1) {
  311. int newIndex;
  312. if (oldIndex > indexOfSibling) {
  313. newIndex = indexOfSibling + 1;
  314. } else {
  315. newIndex = indexOfSibling;
  316. }
  317. childrenList.remove(oldIndex);
  318. childrenList.add(newIndex, itemId);
  319. } else {
  320. throw new IllegalArgumentException(
  321. "Given identifiers no not have the same parent.");
  322. }
  323. }
  324. fireItemSetChange();
  325. }
  326. /*
  327. * (non-Javadoc)
  328. *
  329. * @see com.vaadin.data.util.IndexedContainer#addItem()
  330. */
  331. @Override
  332. public Object addItem() {
  333. disableContentsChangeEvents();
  334. final Object itemId = super.addItem();
  335. if (itemId == null) {
  336. return null;
  337. }
  338. if (!roots.contains(itemId)) {
  339. roots.add(itemId);
  340. if (filteredRoots != null) {
  341. if (passesFilters(itemId)) {
  342. filteredRoots.add(itemId);
  343. }
  344. }
  345. }
  346. enableAndFireContentsChangeEvents();
  347. return itemId;
  348. }
  349. @Override
  350. protected void fireItemSetChange(
  351. com.vaadin.data.Container.ItemSetChangeEvent event) {
  352. if (contentsChangeEventsOn()) {
  353. super.fireItemSetChange(event);
  354. } else {
  355. contentsChangedEventPending = true;
  356. }
  357. }
  358. private boolean contentsChangeEventsOn() {
  359. return !contentChangedEventsDisabled;
  360. }
  361. private void disableContentsChangeEvents() {
  362. contentChangedEventsDisabled = true;
  363. }
  364. private void enableAndFireContentsChangeEvents() {
  365. contentChangedEventsDisabled = false;
  366. if (contentsChangedEventPending) {
  367. fireItemSetChange();
  368. }
  369. contentsChangedEventPending = false;
  370. }
  371. /*
  372. * (non-Javadoc)
  373. *
  374. * @see com.vaadin.data.util.IndexedContainer#addItem(java.lang.Object)
  375. */
  376. @Override
  377. public Item addItem(Object itemId) {
  378. disableContentsChangeEvents();
  379. final Item item = super.addItem(itemId);
  380. if (item == null) {
  381. return null;
  382. }
  383. roots.add(itemId);
  384. if (filteredRoots != null) {
  385. if (passesFilters(itemId)) {
  386. filteredRoots.add(itemId);
  387. }
  388. }
  389. enableAndFireContentsChangeEvents();
  390. return item;
  391. }
  392. /*
  393. * (non-Javadoc)
  394. *
  395. * @see com.vaadin.data.util.IndexedContainer#removeAllItems()
  396. */
  397. @Override
  398. public boolean removeAllItems() {
  399. disableContentsChangeEvents();
  400. final boolean success = super.removeAllItems();
  401. if (success) {
  402. roots.clear();
  403. parent.clear();
  404. children.clear();
  405. noChildrenAllowed.clear();
  406. if (filteredRoots != null) {
  407. filteredRoots = null;
  408. }
  409. if (filteredChildren != null) {
  410. filteredChildren = null;
  411. }
  412. if (filteredParent != null) {
  413. filteredParent = null;
  414. }
  415. }
  416. enableAndFireContentsChangeEvents();
  417. return success;
  418. }
  419. /*
  420. * (non-Javadoc)
  421. *
  422. * @see com.vaadin.data.util.IndexedContainer#removeItem(java.lang.Object )
  423. */
  424. @Override
  425. public boolean removeItem(Object itemId) {
  426. disableContentsChangeEvents();
  427. final boolean success = super.removeItem(itemId);
  428. if (success) {
  429. // Remove from roots if this was a root
  430. if (roots.remove(itemId)) {
  431. // If filtering is enabled we might need to remove it from the
  432. // filtered list also
  433. if (filteredRoots != null) {
  434. filteredRoots.remove(itemId);
  435. }
  436. }
  437. // Clear the children list. Old children will now become root nodes
  438. LinkedList<Object> childNodeIds = children.remove(itemId);
  439. if (childNodeIds != null) {
  440. if (filteredChildren != null) {
  441. filteredChildren.remove(itemId);
  442. }
  443. for (Object childId : childNodeIds) {
  444. setParent(childId, null);
  445. }
  446. }
  447. // Parent of the item that we are removing will contain the item id
  448. // in its children list
  449. final Object parentItemId = parent.get(itemId);
  450. if (parentItemId != null) {
  451. final LinkedList<Object> c = children.get(parentItemId);
  452. if (c != null) {
  453. c.remove(itemId);
  454. if (c.isEmpty()) {
  455. children.remove(parentItemId);
  456. }
  457. // Found in the children list so might also be in the
  458. // filteredChildren list
  459. if (filteredChildren != null) {
  460. LinkedList<Object> f = filteredChildren
  461. .get(parentItemId);
  462. if (f != null) {
  463. f.remove(itemId);
  464. if (f.isEmpty()) {
  465. filteredChildren.remove(parentItemId);
  466. }
  467. }
  468. }
  469. }
  470. }
  471. parent.remove(itemId);
  472. if (filteredParent != null) {
  473. // Item id no longer has a parent as the item id is not in the
  474. // container.
  475. filteredParent.remove(itemId);
  476. }
  477. noChildrenAllowed.remove(itemId);
  478. }
  479. enableAndFireContentsChangeEvents();
  480. return success;
  481. }
  482. /**
  483. * Removes the Item identified by given itemId and all its children.
  484. *
  485. * @see #removeItem(Object)
  486. * @param itemId
  487. * the identifier of the Item to be removed
  488. * @return true if the operation succeeded
  489. */
  490. public boolean removeItemRecursively(Object itemId) {
  491. disableContentsChangeEvents();
  492. boolean removeItemRecursively = removeItemRecursively(this, itemId);
  493. enableAndFireContentsChangeEvents();
  494. return removeItemRecursively;
  495. }
  496. /**
  497. * Removes the Item identified by given itemId and all its children from the
  498. * given Container.
  499. *
  500. * @param container
  501. * the container where the item is to be removed
  502. * @param itemId
  503. * the identifier of the Item to be removed
  504. * @return true if the operation succeeded
  505. */
  506. public static boolean removeItemRecursively(
  507. Container.Hierarchical container, Object itemId) {
  508. boolean success = true;
  509. Collection<?> children2 = container.getChildren(itemId);
  510. if (children2 != null) {
  511. Object[] array = children2.toArray();
  512. for (int i = 0; i < array.length; i++) {
  513. boolean removeItemRecursively = removeItemRecursively(
  514. container, array[i]);
  515. if (!removeItemRecursively) {
  516. success = false;
  517. }
  518. }
  519. }
  520. // remove the root of subtree if children where succesfully removed
  521. if (success) {
  522. success = container.removeItem(itemId);
  523. }
  524. return success;
  525. }
  526. /*
  527. * (non-Javadoc)
  528. *
  529. * @see com.vaadin.data.util.IndexedContainer#doSort()
  530. */
  531. @Override
  532. protected void doSort() {
  533. super.doSort();
  534. Collections.sort(roots, getItemSorter());
  535. for (LinkedList<Object> childList : children.values()) {
  536. Collections.sort(childList, getItemSorter());
  537. }
  538. }
  539. /**
  540. * Used to control how filtering works. @see
  541. * {@link #setIncludeParentsWhenFiltering(boolean)} for more information.
  542. *
  543. * @return true if all parents for items that match the filter are included
  544. * when filtering, false if only the matching items are included
  545. */
  546. public boolean isIncludeParentsWhenFiltering() {
  547. return includeParentsWhenFiltering;
  548. }
  549. /**
  550. * Controls how the filtering of the container works. Set this to true to
  551. * make filtering include parents for all matched items in addition to the
  552. * items themselves. Setting this to false causes the filtering to only
  553. * include the matching items and make items with excluded parents into root
  554. * items.
  555. *
  556. * @param includeParentsWhenFiltering
  557. * true to include all parents for items that match the filter,
  558. * false to only include the matching items
  559. */
  560. public void setIncludeParentsWhenFiltering(
  561. boolean includeParentsWhenFiltering) {
  562. this.includeParentsWhenFiltering = includeParentsWhenFiltering;
  563. if (filteredRoots != null) {
  564. // Currently filtered so needs to be re-filtered
  565. doFilterContainer(true);
  566. }
  567. }
  568. /*
  569. * Overridden to provide filtering for root & children items.
  570. *
  571. * (non-Javadoc)
  572. *
  573. * @see com.vaadin.data.util.IndexedContainer#updateContainerFiltering()
  574. */
  575. @Override
  576. protected boolean doFilterContainer(boolean hasFilters) {
  577. if (!hasFilters) {
  578. // All filters removed
  579. filteredRoots = null;
  580. filteredChildren = null;
  581. filteredParent = null;
  582. return super.doFilterContainer(hasFilters);
  583. }
  584. // Reset data structures
  585. filteredRoots = new LinkedList<Object>();
  586. filteredChildren = new HashMap<Object, LinkedList<Object>>();
  587. filteredParent = new HashMap<Object, Object>();
  588. if (includeParentsWhenFiltering) {
  589. // Filter so that parents for items that match the filter are also
  590. // included
  591. HashSet<Object> includedItems = new HashSet<Object>();
  592. for (Object rootId : roots) {
  593. if (filterIncludingParents(rootId, includedItems)) {
  594. filteredRoots.add(rootId);
  595. addFilteredChildrenRecursively(rootId, includedItems);
  596. }
  597. }
  598. // includedItemIds now contains all the item ids that should be
  599. // included. Filter IndexedContainer based on this
  600. filterOverride = includedItems;
  601. super.doFilterContainer(hasFilters);
  602. filterOverride = null;
  603. return true;
  604. } else {
  605. // Filter by including all items that pass the filter and make items
  606. // with no parent new root items
  607. // Filter IndexedContainer first so getItemIds return the items that
  608. // match
  609. super.doFilterContainer(hasFilters);
  610. LinkedHashSet<Object> filteredItemIds = new LinkedHashSet<Object>(
  611. getItemIds());
  612. for (Object itemId : filteredItemIds) {
  613. Object itemParent = parent.get(itemId);
  614. if (itemParent == null || !filteredItemIds.contains(itemParent)) {
  615. // Parent is not included or this was a root, in both cases
  616. // this should be a filtered root
  617. filteredRoots.add(itemId);
  618. } else {
  619. // Parent is included. Add this to the children list (create
  620. // it first if necessary)
  621. addFilteredChild(itemParent, itemId);
  622. }
  623. }
  624. return true;
  625. }
  626. }
  627. /**
  628. * Adds the given childItemId as a filteredChildren for the parentItemId and
  629. * sets it filteredParent.
  630. *
  631. * @param parentItemId
  632. * @param childItemId
  633. */
  634. private void addFilteredChild(Object parentItemId, Object childItemId) {
  635. LinkedList<Object> parentToChildrenList = filteredChildren
  636. .get(parentItemId);
  637. if (parentToChildrenList == null) {
  638. parentToChildrenList = new LinkedList<Object>();
  639. filteredChildren.put(parentItemId, parentToChildrenList);
  640. }
  641. filteredParent.put(childItemId, parentItemId);
  642. parentToChildrenList.add(childItemId);
  643. }
  644. /**
  645. * Recursively adds all items in the includedItems list to the
  646. * filteredChildren map in the same order as they are in the children map.
  647. * Starts from parentItemId and recurses down as long as child items that
  648. * should be included are found.
  649. *
  650. * @param parentItemId
  651. * The item id to start recurse from. Not added to a
  652. * filteredChildren list
  653. * @param includedItems
  654. * Set containing the item ids for the items that should be
  655. * included in the filteredChildren map
  656. */
  657. private void addFilteredChildrenRecursively(Object parentItemId,
  658. HashSet<Object> includedItems) {
  659. LinkedList<Object> childList = children.get(parentItemId);
  660. if (childList == null) {
  661. return;
  662. }
  663. for (Object childItemId : childList) {
  664. if (includedItems.contains(childItemId)) {
  665. addFilteredChild(parentItemId, childItemId);
  666. addFilteredChildrenRecursively(childItemId, includedItems);
  667. }
  668. }
  669. }
  670. /**
  671. * Scans the itemId and all its children for which items should be included
  672. * when filtering. All items which passes the filters are included.
  673. * Additionally all items that have a child node that should be included are
  674. * also themselves included.
  675. *
  676. * @param itemId
  677. * @param includedItems
  678. * @return true if the itemId should be included in the filtered container.
  679. */
  680. private boolean filterIncludingParents(Object itemId,
  681. HashSet<Object> includedItems) {
  682. boolean toBeIncluded = passesFilters(itemId);
  683. LinkedList<Object> childList = children.get(itemId);
  684. if (childList != null) {
  685. for (Object childItemId : children.get(itemId)) {
  686. toBeIncluded |= filterIncludingParents(childItemId,
  687. includedItems);
  688. }
  689. }
  690. if (toBeIncluded) {
  691. includedItems.add(itemId);
  692. }
  693. return toBeIncluded;
  694. }
  695. private Set<Object> filterOverride = null;
  696. /*
  697. * (non-Javadoc)
  698. *
  699. * @see
  700. * com.vaadin.data.util.IndexedContainer#passesFilters(java.lang.Object)
  701. */
  702. @Override
  703. protected boolean passesFilters(Object itemId) {
  704. if (filterOverride != null) {
  705. return filterOverride.contains(itemId);
  706. } else {
  707. return super.passesFilters(itemId);
  708. }
  709. }
  710. }