]> source.dussan.org Git - vaadin-framework.git/commitdiff
Updated test case and fix for #4192 "HierarchicalContainer implements Container.Filte...
authorArtur Signell <artur.signell@itmill.com>
Tue, 16 Mar 2010 08:10:55 +0000 (08:10 +0000)
committerArtur Signell <artur.signell@itmill.com>
Tue, 16 Mar 2010 08:10:55 +0000 (08:10 +0000)
svn changeset:11901/svn branch:6.3

src/com/vaadin/data/util/HierarchicalContainer.java
src/com/vaadin/data/util/IndexedContainer.java
tests/src/com/vaadin/tests/components/tree/TreeFiltering.java
tests/src/com/vaadin/tests/server/container/AbstractHierarchicalContainerTest.java
tests/src/com/vaadin/tests/server/container/TestHierarchicalContainer.java

index 5d29283bcb2120cf881b274057b9ef736732b11f..152d9b4e584283d435f60ad1737e0ff49b298f68 100644 (file)
@@ -8,7 +8,9 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.LinkedList;
+import java.util.Set;
 
 import com.vaadin.data.Container;
 import com.vaadin.data.Item;
@@ -32,10 +34,16 @@ public class HierarchicalContainer extends IndexedContainer implements
     private final HashSet<Object> noChildrenAllowed = new HashSet<Object>();
 
     /**
-     * Mapping from Item ID to parent Item.
+     * Mapping from Item ID to parent Item ID.
      */
     private final HashMap<Object, Object> parent = new HashMap<Object, Object>();
 
+    /**
+     * Mapping from Item ID to parent Item ID for items included in the filtered
+     * container.
+     */
+    private HashMap<Object, Object> filteredParent = null;
+
     /**
      * Mapping from Item ID to a list of child IDs.
      */
@@ -56,6 +64,11 @@ public class HierarchicalContainer extends IndexedContainer implements
      */
     private LinkedList<Object> filteredRoots = null;
 
+    /**
+     * Determines how filtering of the container is done.
+     */
+    private boolean includeParentsWhenFiltering = true;
+
     /*
      * Can the specified Item have any children? Don't add a JavaDoc comment
      * here, we use the default documentation from implemented interface.
@@ -93,6 +106,9 @@ public class HierarchicalContainer extends IndexedContainer implements
      * interface.
      */
     public Object getParent(Object itemId) {
+        if (filteredParent != null) {
+            return filteredParent.get(itemId);
+        }
         return parent.get(itemId);
     }
 
@@ -115,12 +131,17 @@ public class HierarchicalContainer extends IndexedContainer implements
      * interface.
      */
     public boolean isRoot(Object itemId) {
-        if (filteredRoots != null && !filteredRoots.contains(itemId)) {
-            return false;
-        }
-
-        if (parent.containsKey(itemId)) {
-            return false;
+        // If the container is filtered the itemId must be among filteredRoots
+        // to be a root.
+        if (filteredRoots != null) {
+            if (!filteredRoots.contains(itemId)) {
+                return false;
+            }
+        } else {
+            // Container is not filtered
+            if (parent.containsKey(itemId)) {
+                return false;
+            }
         }
 
         return containsId(itemId);
@@ -211,8 +232,7 @@ public class HierarchicalContainer extends IndexedContainer implements
         // Making root?
         if (newParentId == null) {
             // The itemId should become a root so we need to
-            // - Remove it from the old parent's children list (also filtered
-            // list)
+            // - Remove it from the old parent's children list
             // - Add it as a root
             // - Remove it from the item -> parent list (parent is null for
             // roots)
@@ -225,28 +245,21 @@ public class HierarchicalContainer extends IndexedContainer implements
                     children.remove(itemId);
                 }
 
-                if (filteredChildren != null) {
-                    LinkedList<Object> f = filteredChildren.get(itemId);
-                    if (f != null) {
-                        f.remove(itemId);
-                        if (f.isEmpty()) {
-                            filteredChildren.remove(f);
-                        }
-                    }
-                }
             }
 
             // Add to be a root
             roots.add(itemId);
-            if (filteredRoots != null) {
-                if (passesFilters(itemId)) {
-                    filteredRoots.add(itemId);
-                }
-            }
 
             // Updates parent
             parent.remove(itemId);
 
+            if (hasFilters()) {
+                // Refilter the container if setParent is called when filters
+                // are applied. Changing parent can change what is included in
+                // the filtered version (if includeParentsWhenFiltering==true).
+                doFilterContainer(hasFilters());
+            }
+
             fireContentsChange(-1);
 
             return true;
@@ -286,17 +299,6 @@ public class HierarchicalContainer extends IndexedContainer implements
         }
         pcl.add(itemId);
 
-        // Add children list for filtered case also
-        if (filteredChildren != null) {
-            LinkedList<Object> f = filteredChildren.get(newParentId);
-            if (f == null) {
-                // Create an empty list for holding children if one were not
-                // previously created
-                f = new LinkedList<Object>();
-                filteredChildren.put(newParentId, f);
-            }
-        }
-
         // Removes from old parent or root
         if (oldParentId == null) {
             roots.remove(itemId);
@@ -308,15 +310,13 @@ public class HierarchicalContainer extends IndexedContainer implements
                     children.remove(oldParentId);
                 }
             }
-            if (filteredChildren != null) {
-                LinkedList<Object> f = filteredChildren.get(oldParentId);
-                if (f != null) {
-                    f.remove(itemId);
-                    if (f.isEmpty()) {
-                        filteredChildren.remove(oldParentId);
-                    }
-                }
-            }
+        }
+
+        if (hasFilters()) {
+            // Refilter the container if setParent is called when filters
+            // are applied. Changing parent can change what is included in
+            // the filtered version (if includeParentsWhenFiltering==true).
+            doFilterContainer(hasFilters());
         }
 
         fireContentsChange(-1);
@@ -324,6 +324,10 @@ public class HierarchicalContainer extends IndexedContainer implements
         return true;
     }
 
+    private boolean hasFilters() {
+        return (filteredRoots != null);
+    }
+
     /**
      * TODO javadoc
      * 
@@ -550,6 +554,33 @@ public class HierarchicalContainer extends IndexedContainer implements
         }
     }
 
+    /**
+     * Used to control how filtering works. @see
+     * {@link #setIncludeParentsWhenFiltering(boolean)} for more information.
+     * 
+     * @return true if all parents for items that match the filter are included
+     *         when filtering, false if only the matching items are included
+     */
+    public boolean isIncludeParentsWhenFiltering() {
+        return includeParentsWhenFiltering;
+    }
+
+    /**
+     * Controls how the filtering of the container works. Set this to true to
+     * make filtering include parents for all matched items in addition to the
+     * items themselves. Setting this to false causes the filtering to only
+     * include the matching items and make items with excluded parents into root
+     * items.
+     * 
+     * @param includeParentsWhenFiltering
+     *            true to include all parents for items that match the filter,
+     *            false to only include the matching items
+     */
+    public void setIncludeParentsWhenFiltering(
+            boolean includeParentsWhenFiltering) {
+        this.includeParentsWhenFiltering = includeParentsWhenFiltering;
+    }
+
     /*
      * Overridden to provide filtering for root & children items.
      * 
@@ -558,32 +589,154 @@ public class HierarchicalContainer extends IndexedContainer implements
      * @see com.vaadin.data.util.IndexedContainer#updateContainerFiltering()
      */
     @Override
-    protected void updateContainerFiltering() {
-        super.updateContainerFiltering();
+    protected boolean doFilterContainer(boolean hasFilters) {
+        if (!hasFilters) {
+            // All filters removed
+            filteredRoots = null;
+            filteredChildren = null;
 
+            return super.doFilterContainer(hasFilters);
+        }
+
+        // Reset data structures
         filteredRoots = new LinkedList<Object>();
         filteredChildren = new HashMap<Object, LinkedList<Object>>();
+        filteredParent = new HashMap<Object, Object>();
+
+        if (includeParentsWhenFiltering) {
+            // Filter so that parents for items that match the filter are also
+            // included
+            HashSet<Object> includedItems = new HashSet<Object>();
+            for (Object rootId : roots) {
+                if (filterIncludingParents(rootId, includedItems)) {
+                    filteredRoots.add(rootId);
+                    addFilteredChildrenRecursively(rootId, includedItems);
+                }
+            }
+            // includedItemIds now contains all the item ids that should be
+            // included. Filter IndexedContainer based on this
+            filterOverride = includedItems;
+            super.doFilterContainer(hasFilters);
+            filterOverride = null;
+
+            return true;
+        } else {
+            // Filter by including all items that pass the filter and make items
+            // with no parent new root items
+
+            // Filter IndexedContainer first so getItemIds return the items that
+            // match
+            super.doFilterContainer(hasFilters);
+
+            LinkedHashSet<Object> filteredItemIds = new LinkedHashSet<Object>(
+                    getItemIds());
 
-        // Filter root item ids
-        for (Object rootId : roots) {
-            if (passesFilters(rootId)) {
-                filteredRoots.add(rootId);
+            for (Object itemId : filteredItemIds) {
+                Object itemParent = parent.get(itemId);
+                if (itemParent == null || !filteredItemIds.contains(itemParent)) {
+                    // Parent is not included or this was a root, in both cases
+                    // this should be a filtered root
+                    filteredRoots.add(itemId);
+                } else {
+                    // Parent is included. Add this to the children list (create
+                    // it first if necessary)
+                    addFilteredChild(itemParent, itemId);
+                }
             }
+
+            return true;
         }
+    }
 
-        // Filter children
-        for (Object parent : children.keySet()) {
-            if (passesFilters(parent)) {
-                LinkedList<Object> filtered = new LinkedList<Object>();
-                filteredChildren.put(parent, filtered);
-                for (Object child : children.get(parent)) {
-                    if (passesFilters(child)) {
-                        filtered.add(child);
-                    }
-                }
+    /**
+     * Adds the given childItemId as a filteredChildren for the parentItemId and
+     * sets it filteredParent.
+     * 
+     * @param parentItemId
+     * @param childItemId
+     */
+    private void addFilteredChild(Object parentItemId, Object childItemId) {
+        LinkedList<Object> parentToChildrenList = filteredChildren
+                .get(parentItemId);
+        if (parentToChildrenList == null) {
+            parentToChildrenList = new LinkedList<Object>();
+            filteredChildren.put(parentItemId, parentToChildrenList);
+        }
+        filteredParent.put(childItemId, parentItemId);
+        parentToChildrenList.add(childItemId);
+
+    }
+
+    /**
+     * Recursively adds all items in the includedItems list to the
+     * filteredChildren map in the same order as they are in the children map.
+     * Starts from parentItemId and recurses down as long as child items that
+     * should be included are found.
+     * 
+     * @param parentItemId
+     *            The item id to start recurse from. Not added to a
+     *            filteredChildren list
+     * @param includedItems
+     *            Set containing the item ids for the items that should be
+     *            included in the filteredChildren map
+     */
+    private void addFilteredChildrenRecursively(Object parentItemId,
+            HashSet<Object> includedItems) {
+        LinkedList<Object> childList = children.get(parentItemId);
+        if (childList == null) {
+            return;
+        }
+
+        for (Object childItemId : childList) {
+            if (includedItems.contains(childItemId)) {
+                addFilteredChild(parentItemId, childItemId);
+                addFilteredChildrenRecursively(childItemId, includedItems);
             }
         }
+    }
 
+    /**
+     * Scans the itemId and all its children for which items should be included
+     * when filtering. All items which passes the filters are included.
+     * Additionally all items that have a child node that should be included are
+     * also themselves included.
+     * 
+     * @param itemId
+     * @param includedItems
+     * @return true if the itemId should be included in the filtered container.
+     */
+    private boolean filterIncludingParents(Object itemId,
+            HashSet<Object> includedItems) {
+        boolean toBeIncluded = passesFilters(itemId);
+
+        LinkedList<Object> childList = children.get(itemId);
+        if (childList != null) {
+            for (Object childItemId : children.get(itemId)) {
+                toBeIncluded |= filterIncludingParents(childItemId,
+                        includedItems);
+            }
+        }
+
+        if (toBeIncluded) {
+            includedItems.add(itemId);
+        }
+        return toBeIncluded;
     }
 
+    private Set<Object> filterOverride = null;
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * com.vaadin.data.util.IndexedContainer#passesFilters(java.lang.Object)
+     */
+    @Override
+    protected boolean passesFilters(Object itemId) {
+        if (filterOverride != null) {
+            return filterOverride.contains(itemId);
+        } else {
+            return super.passesFilters(itemId);
+        }
+    }
 }
index bd3c14180da9bc06475cfc43986d2a36e02dbf49..2f6bae98512cf5ebb4a01e8d8f6fb7e914f093da 100644 (file)
@@ -58,7 +58,7 @@ public class IndexedContainer implements Container.Indexed,
     private ArrayList<Object> itemIds = new ArrayList<Object>();
 
     /** List of item ids that passes the filtering */
-    private LinkedHashSet filteredItemIds = null;
+    private LinkedHashSet<Object> filteredItemIds = null;
 
     /**
      * Linked list of ordered Property IDs.
@@ -329,9 +329,8 @@ public class IndexedContainer implements Container.Indexed,
 
         // this optimization is why some code is duplicated with
         // addItemAtInternalIndex()
-        final Item item = new IndexedContainerItem(itemId);
         if (filteredItemIds != null) {
-            if (passesFilters(item)) {
+            if (passesFilters(itemId)) {
                 filteredItemIds.add(itemId);
             }
         }
@@ -339,7 +338,7 @@ public class IndexedContainer implements Container.Indexed,
         // Sends the event
         fireContentsChange(itemIds.size() - 1);
 
-        return item;
+        return new IndexedContainerItem(itemId);
     }
 
     /**
@@ -1560,18 +1559,42 @@ public class IndexedContainer implements Container.Indexed,
         }
     }
 
-    protected void updateContainerFiltering() {
+    /**
+     * Called when the filters have changed or when another event that effects
+     * filtering has taken place. Updates internal data structures and fires an
+     * item set change if necessary.
+     */
+    private void updateContainerFiltering() {
 
         // Clearing filters?
-        if (filters == null || filters.isEmpty()) {
+        boolean hasFilters = (filters != null && !filters.isEmpty());
+
+        if (doFilterContainer(hasFilters)) {
+            fireContentsChange(-1);
+        }
+    }
+
+    /**
+     * Filters the data in the container and updates internal data structures.
+     * This method should reset any internal data structures and then repopulate
+     * them so {@link #getItemIds()} and other methods only return the filtered
+     * items.
+     * 
+     * @param hasFilters
+     *            true if filters has been set for the container, false
+     *            otherwise
+     * @return true if the item set has changed as a result of the filtering
+     */
+    protected boolean doFilterContainer(boolean hasFilters) {
+        if (!hasFilters) {
             filteredItemIds = null;
             if (filters != null) {
                 filters = null;
-                fireContentsChange(-1);
+                return true;
             }
-            return;
-        }
 
+            return false;
+        }
         // Reset filtered list
         if (filteredItemIds == null) {
             filteredItemIds = new LinkedHashSet();
@@ -1587,14 +1610,22 @@ public class IndexedContainer implements Container.Indexed,
             }
         }
 
-        fireContentsChange(-1);
-    }
+        return true;
 
-    protected final boolean passesFilters(Object itemId) {
-        return passesFilters(new IndexedContainerItem(itemId));
     }
 
-    private boolean passesFilters(Item item) {
+    /**
+     * Checks if the given itemId passes the filters set for the container. The
+     * caller should make sure the itemId exists in the container. For
+     * non-existing itemIds the behavior is undefined.
+     * 
+     * @param itemId
+     *            An itemId that exists in the container.
+     * @return true if the itemId passes all filters or no filters are set,
+     *         false otherwise.
+     */
+    protected boolean passesFilters(Object itemId) {
+        IndexedContainerItem item = new IndexedContainerItem(itemId);
         if (filters == null) {
             return true;
         }
index 495e6cfb96a44c12bea69bf7e42e0b8e43e025ab..25d7a510f18ca1251ae44f80209812a7a09b1025 100644 (file)
@@ -1,9 +1,12 @@
 package com.vaadin.tests.components.tree;\r
 \r
 import com.vaadin.data.Item;\r
+import com.vaadin.data.Property.ValueChangeEvent;\r
+import com.vaadin.data.Property.ValueChangeListener;\r
 import com.vaadin.data.util.HierarchicalContainer;\r
 import com.vaadin.tests.components.TestBase;\r
 import com.vaadin.ui.Button;\r
+import com.vaadin.ui.CheckBox;\r
 import com.vaadin.ui.Tree;\r
 import com.vaadin.ui.Button.ClickEvent;\r
 import com.vaadin.ui.Button.ClickListener;\r
@@ -39,6 +42,17 @@ public class TreeFiltering extends TestBase {
             ccTree.expandItem(o);\r
         }\r
 \r
+        final CheckBox filterType = new CheckBox(\r
+                "Include parent when filtering", true);\r
+        filterType.addListener(new ValueChangeListener() {\r
+\r
+            public void valueChange(ValueChangeEvent event) {\r
+                cont.setIncludeParentsWhenFiltering(((CheckBox) event\r
+                        .getProperty()).booleanValue());\r
+            }\r
+        });\r
+        addComponent(filterType);\r
+\r
         final Button b = new Button("Add filter 'foo'", new ClickListener() {\r
             public void buttonClick(final ClickEvent event) {\r
                 cont.addContainerFilter("caption", "foo", true, false);\r
@@ -62,7 +76,33 @@ public class TreeFiltering extends TestBase {
         });\r
 \r
         addComponent(num);\r
-        final Button r = new Button("Remove filter", new ClickListener() {\r
+        final Button num2 = new Button("Add filter '0-'", new ClickListener() {\r
+            public void buttonClick(final ClickEvent event) {\r
+                cont.addContainerFilter("caption", "0-", true, false);\r
+\r
+            }\r
+        });\r
+\r
+        addComponent(num2);\r
+        final Button num3 = new Button("Add filter 'Number 4'",\r
+                new ClickListener() {\r
+                    public void buttonClick(final ClickEvent event) {\r
+                        cont.addContainerFilter("caption", "Number 4", true,\r
+                                false);\r
+\r
+                    }\r
+                });\r
+\r
+        addComponent(num3);\r
+        final Button p1 = new Button("Set Number 3 parent to Number 0",\r
+                new ClickListener() {\r
+                    public void buttonClick(final ClickEvent event) {\r
+                        cont.setParent(3, 0);\r
+\r
+                    }\r
+                });\r
+        addComponent(p1);\r
+        final Button r = new Button("Remove filters", new ClickListener() {\r
             public void buttonClick(final ClickEvent event) {\r
                 cont.removeAllContainerFilters();\r
 \r
index 7aeef3e1b16f613d74d404c2b346b9212164e941..a85e0dd34b228c938868c552e815ce2c0a0ec826 100644 (file)
@@ -28,12 +28,14 @@ public class AbstractHierarchicalContainerTest extends AbstractContainerTest {
      *            down to all available nodes.\r
      * @param expectedRootSize\r
      *            Expected number of root items\r
+     * @param rootsHaveChildren\r
+     *            true if all roots have children, false otherwise (skips some\r
+     *            asserts)\r
      */\r
-    private void validateHierarchicalContainer(Hierarchical container,\r
+    protected void validateHierarchicalContainer(Hierarchical container,\r
             Object expectedFirstItemId, Object expectedLastItemId,\r
-            Object itemIdInSet, Object itemIdNotInSet,\r
-            boolean rootsHaveChildren, int expectedSize,\r
-            int expectedTraversalSize, int expectedRootSize) {\r
+            Object itemIdInSet, Object itemIdNotInSet, int expectedSize,\r
+            int expectedRootSize, boolean rootsHaveChildren) {\r
 \r
         validateContainer(container, expectedFirstItemId, expectedLastItemId,\r
                 itemIdInSet, itemIdNotInSet, expectedSize);\r
@@ -52,21 +54,19 @@ public class AbstractHierarchicalContainerTest extends AbstractContainerTest {
             // all roots must be roots\r
             assertTrue(container.isRoot(rootId));\r
 \r
-            // all roots have children allowed in this case\r
-            assertTrue(container.areChildrenAllowed(rootId));\r
-\r
-            // all roots have children in this case\r
             if (rootsHaveChildren) {\r
+                // all roots have children allowed in this case\r
+                assertTrue(container.areChildrenAllowed(rootId));\r
+\r
+                // all roots have children in this case\r
                 Collection<?> children = container.getChildren(rootId);\r
                 assertNotNull(rootId + " should have children", children);\r
                 assertTrue(rootId + " should have children",\r
                         (children.size() > 0));\r
-\r
                 // getParent\r
                 for (Object childId : children) {\r
                     assertEquals(container.getParent(childId), rootId);\r
                 }\r
-            } else {\r
 \r
             }\r
         }\r
@@ -83,7 +83,7 @@ public class AbstractHierarchicalContainerTest extends AbstractContainerTest {
         // removeItem of unknown items should return false\r
         assertFalse(container.removeItem(itemIdNotInSet));\r
 \r
-        assertEquals(expectedTraversalSize, countNodes(container));\r
+        assertEquals(expectedSize, countNodes(container));\r
 \r
         validateHierarchy(container);\r
     }\r
@@ -143,8 +143,8 @@ public class AbstractHierarchicalContainerTest extends AbstractContainerTest {
         int expectedSize = sampleData.length + packages;\r
         validateHierarchicalContainer(container, "com",\r
                 "com.vaadin.util.SerializerHelper",\r
-                "com.vaadin.terminal.ApplicationResource", "blah", true,\r
-                expectedSize, expectedSize, 1);\r
+                "com.vaadin.terminal.ApplicationResource", "blah",\r
+                expectedSize, 1, true);\r
 \r
     }\r
 \r
@@ -166,8 +166,8 @@ public class AbstractHierarchicalContainerTest extends AbstractContainerTest {
         int expectedSize = sampleData.length + packages;\r
         validateHierarchicalContainer(container, "com",\r
                 "com.vaadin.util.SerializerHelper",\r
-                "com.vaadin.terminal.ApplicationResource", "blah", true,\r
-                expectedSize, expectedSize, 1);\r
+                "com.vaadin.terminal.ApplicationResource", "blah",\r
+                expectedSize, 1, true);\r
 \r
         sortable.sort(new Object[] { REVERSE_FULLY_QUALIFIED_NAME },\r
                 new boolean[] { true });\r
@@ -175,58 +175,8 @@ public class AbstractHierarchicalContainerTest extends AbstractContainerTest {
         validateHierarchicalContainer(container,\r
                 "com.vaadin.terminal.gwt.server.ApplicationPortlet2",\r
                 "com.vaadin.data.util.ObjectProperty",\r
-                "com.vaadin.terminal.ApplicationResource", "blah", true,\r
-                expectedSize, expectedSize, 1);\r
-\r
-    }\r
-\r
-    protected void testHierarchicalFiltering(Container.Hierarchical container) {\r
-        Container.Filterable filterable = (Container.Filterable) container;\r
-\r
-        initializeContainer(container);\r
-\r
-        // Filter by "contains ab"\r
-        filterable.addContainerFilter(FULLY_QUALIFIED_NAME, "ab", false, false);\r
-\r
-        // 20 items should remain in the container but the root should be\r
-        // filtered\r
-        int expectedSize = 20;\r
-        int expectedTraversalSize = 0;\r
-        int expectedRoots = 0;\r
-\r
-        validateHierarchicalContainer(container,\r
-                "com.vaadin.data.BufferedValidatable",\r
-                "com.vaadin.ui.TabSheet",\r
-                "com.vaadin.terminal.gwt.client.Focusable", "blah", true,\r
-                expectedSize, expectedTraversalSize, expectedRoots);\r
-\r
-        // filter out every second item except hierarchy items\r
-        filterable.removeAllContainerFilters();\r
-        filterable.addContainerFilter(ID_NUMBER, "1", false, false);\r
-\r
-        int packages = 21;\r
-        int other = sampleData.length / 2;\r
-\r
-        expectedSize = packages + other;\r
-        expectedRoots = 1;\r
-        expectedTraversalSize = expectedSize;\r
-\r
-        validateHierarchicalContainer(container, "com", "com.vaadin.util",\r
-                "com.vaadin.data.util.IndexedContainer", "blah", true,\r
-                expectedSize, expectedTraversalSize, expectedRoots);\r
-\r
-        // Additionally remove all without 'm' in the simple name. Hierarchy is\r
-        // now one root only.\r
-        filterable.addContainerFilter(SIMPLE_NAME, "m", false, false);\r
-\r
-        expectedSize = 27;\r
-        expectedRoots = 1;\r
-        expectedTraversalSize = 1;\r
-\r
-        validateHierarchicalContainer(container, "com",\r
-                "com.vaadin.ui.UriFragmentUtility",\r
-                "com.vaadin.terminal.gwt.client.ui.TreeImages", "blah", false,\r
-                expectedSize, expectedTraversalSize, expectedRoots);\r
+                "com.vaadin.terminal.ApplicationResource", "blah",\r
+                expectedSize, 1, true);\r
 \r
     }\r
 \r
index 0f60e133c11ab0a57ce856e35f11916ee0a0f390..02973b35a6d4d04bc67e8a5f5d79ef01ee731832 100644 (file)
@@ -13,10 +13,6 @@ public class TestHierarchicalContainer extends
         testContainerFiltering(new HierarchicalContainer());\r
     }\r
 \r
-    public void testHierarchicalFiltering() {\r
-        testHierarchicalFiltering(new HierarchicalContainer());\r
-    }\r
-\r
     public void testSorting() {\r
         testContainerSorting(new HierarchicalContainer());\r
     }\r
@@ -33,8 +29,127 @@ public class TestHierarchicalContainer extends
         testContainerSortingAndFiltering(new HierarchicalContainer());\r
     }\r
 \r
-    // public void testHierarchicalSortingAndFiltering() {\r
-    // testHierarchicalSortingAndFiltering(new HierarchicalContainer());\r
-    // }\r
+    public void testHierarchicalFilteringWithParents() {\r
+        HierarchicalContainer container = new HierarchicalContainer();\r
+        initializeContainer(container);\r
+        container.setIncludeParentsWhenFiltering(true);\r
+\r
+        // Filter by "contains ab"\r
+        container.addContainerFilter(FULLY_QUALIFIED_NAME, "ab", false, false);\r
+\r
+        // 20 items match the filters and the have 8 parents that should also be\r
+        // included\r
+        // only one root "com" should exist\r
+        // filtered\r
+        int expectedSize = 29;\r
+        int expectedRoots = 1;\r
+\r
+        validateHierarchicalContainer(container, "com",\r
+                "com.vaadin.ui.TabSheet",\r
+                "com.vaadin.terminal.gwt.client.Focusable", "blah",\r
+                expectedSize, expectedRoots, true);\r
+\r
+        // only include .gwt.client classes\r
+        container.removeAllContainerFilters();\r
+        container.addContainerFilter(FULLY_QUALIFIED_NAME, ".gwt.client.",\r
+                false, false);\r
+\r
+        int packages = 6;\r
+        int classes = 112;\r
+\r
+        expectedSize = packages + classes;\r
+        expectedRoots = 1;\r
+\r
+        validateHierarchicalContainer(container, "com",\r
+                "com.vaadin.terminal.gwt.client.WidgetSet",\r
+                "com.vaadin.terminal.gwt.client.ui.VSplitPanelVertical",\r
+                "blah", expectedSize, expectedRoots, true);\r
+\r
+        // Additionally remove all without 'm' in the simple name.\r
+        container.addContainerFilter(SIMPLE_NAME, "m", false, false);\r
+\r
+        expectedSize = 7 + 18;\r
+        expectedRoots = 1;\r
+\r
+        validateHierarchicalContainer(\r
+                container,\r
+                "com",\r
+                "com.vaadin.terminal.gwt.client.ui.VUriFragmentUtility",\r
+                "com.vaadin.terminal.gwt.client.ui.layout.ChildComponentContainer",\r
+                "blah", expectedSize, expectedRoots, true);\r
+\r
+    }\r
 \r
+    public void testHierarchicalFilteringWithoutParents() {\r
+        HierarchicalContainer container = new HierarchicalContainer();\r
+\r
+        initializeContainer(container);\r
+        container.setIncludeParentsWhenFiltering(false);\r
+\r
+        // Filter by "contains ab"\r
+        container.addContainerFilter(SIMPLE_NAME, "ab", false, false);\r
+\r
+        // 20 items match the filter.\r
+        // com.vaadin.data.BufferedValidatable\r
+        // com.vaadin.data.Validatable\r
+        // com.vaadin.terminal.gwt.client.Focusable\r
+        // com.vaadin.terminal.gwt.client.Paintable\r
+        // com.vaadin.terminal.gwt.client.ui.Table\r
+        // com.vaadin.terminal.gwt.client.ui.VLabel\r
+        // com.vaadin.terminal.gwt.client.ui.VScrollTable\r
+        // com.vaadin.terminal.gwt.client.ui.VTablePaging\r
+        // com.vaadin.terminal.gwt.client.ui.VTabsheet\r
+        // com.vaadin.terminal.gwt.client.ui.VTabsheetBase\r
+        // com.vaadin.terminal.gwt.client.ui.VTabsheetPanel\r
+        // com.vaadin.terminal.gwt.server.ChangeVariablesErrorEvent\r
+        // com.vaadin.terminal.Paintable\r
+        // com.vaadin.terminal.Scrollable\r
+        // com.vaadin.terminal.Sizeable\r
+        // com.vaadin.terminal.VariableOwner\r
+        // com.vaadin.ui.Label\r
+        // com.vaadin.ui.Table\r
+        // com.vaadin.ui.TableFieldFactory\r
+        // com.vaadin.ui.TabSheet\r
+        // all become roots.\r
+        int expectedSize = 20;\r
+        int expectedRoots = 20;\r
+\r
+        validateHierarchicalContainer(container,\r
+                "com.vaadin.data.BufferedValidatable",\r
+                "com.vaadin.ui.TabSheet",\r
+                "com.vaadin.terminal.gwt.client.ui.VTabsheetBase", "blah",\r
+                expectedSize, expectedRoots, false);\r
+\r
+        // only include .gwt.client classes\r
+        container.removeAllContainerFilters();\r
+        container.addContainerFilter(FULLY_QUALIFIED_NAME, ".gwt.client.",\r
+                false, false);\r
+\r
+        int packages = 3;\r
+        int classes = 110;\r
+\r
+        expectedSize = packages + classes;\r
+        expectedRoots = 35 + 1; // com.vaadin.terminal.gwt.client.ui +\r
+        // com.vaadin.terminal.gwt.client.*\r
+\r
+        // Sorting is case insensitive\r
+        validateHierarchicalContainer(container,\r
+                "com.vaadin.terminal.gwt.client.ApplicationConfiguration",\r
+                "com.vaadin.terminal.gwt.client.WidgetSet",\r
+                "com.vaadin.terminal.gwt.client.ui.VOptionGroup", "blah",\r
+                expectedSize, expectedRoots, false);\r
+\r
+        // Additionally remove all without 'P' in the simple name.\r
+        container.addContainerFilter(SIMPLE_NAME, "P", false, false);\r
+\r
+        expectedSize = 13;\r
+        expectedRoots = expectedSize;\r
+\r
+        validateHierarchicalContainer(container,\r
+                "com.vaadin.terminal.gwt.client.Paintable",\r
+                "com.vaadin.terminal.gwt.client.ui.VTabsheetPanel",\r
+                "com.vaadin.terminal.gwt.client.ui.VPopupCalendar", "blah",\r
+                expectedSize, expectedRoots, false);\r
+\r
+    }\r
 }\r