]> source.dussan.org Git - vaadin-framework.git/commitdiff
Refactor common methods in in-memory data providers (#9308)
authorAleksi Hietanen <aleksi@vaadin.com>
Tue, 16 May 2017 08:57:02 +0000 (11:57 +0300)
committerPekka Hyvönen <pekka@vaadin.com>
Tue, 16 May 2017 08:57:02 +0000 (11:57 +0300)
* Refactor common methods of InMemoryHierarchicalDataProvider and ListDataProvider to a single interface
* Rename HierarchyData and InMemoryHierarchicalDataProvider, introduce HasHierarchicalDataProvider
* Additionally adds a helper method for recursive constructing
TreeData with a child item provider.

30 files changed:
all/src/main/templates/release-notes.html
documentation/components/components-tree.asciidoc
documentation/components/components-treegrid.asciidoc
documentation/datamodel/datamodel-hierarchical.asciidoc
server/src/main/java/com/vaadin/data/HasHierarchicalDataProvider.java [new file with mode: 0644]
server/src/main/java/com/vaadin/data/HierarchyData.java [deleted file]
server/src/main/java/com/vaadin/data/TreeData.java [new file with mode: 0644]
server/src/main/java/com/vaadin/data/provider/HierarchicalDataCommunicator.java
server/src/main/java/com/vaadin/data/provider/InMemoryDataProvider.java [new file with mode: 0644]
server/src/main/java/com/vaadin/data/provider/InMemoryDataProviderHelpers.java [new file with mode: 0644]
server/src/main/java/com/vaadin/data/provider/InMemoryHierarchicalDataProvider.java [deleted file]
server/src/main/java/com/vaadin/data/provider/ListDataProvider.java
server/src/main/java/com/vaadin/data/provider/TreeDataProvider.java [new file with mode: 0644]
server/src/main/java/com/vaadin/ui/Tree.java
server/src/main/java/com/vaadin/ui/TreeGrid.java
server/src/test/java/com/vaadin/data/provider/InMemoryHierarchicalDataProviderTest.java [deleted file]
server/src/test/java/com/vaadin/data/provider/TreeDataProviderTest.java [new file with mode: 0644]
server/src/test/java/com/vaadin/tests/components/TreeTest.java
server/src/test/java/com/vaadin/tests/components/treegrid/TreeGridTest.java
server/src/test/java/com/vaadin/tests/server/ClassesSerializableTest.java
server/src/test/java/com/vaadin/tests/server/component/treegrid/TreeGridDeclarativeTest.java
uitest/src/main/java/com/vaadin/tests/components/tree/TreeBasicFeatures.java
uitest/src/main/java/com/vaadin/tests/components/treegrid/TreeGridBasicFeatures.java
uitest/src/main/java/com/vaadin/tests/components/treegrid/TreeGridChangingHierarchy.java
uitest/src/main/java/com/vaadin/tests/components/treegrid/TreeGridHugeTree.java
uitest/src/main/java/com/vaadin/tests/components/treegrid/TreeGridHugeTreeNavigation.java
uitest/src/main/java/com/vaadin/tests/components/treegrid/TreeGridInitialExpand.java
uitest/src/main/java/com/vaadin/tests/performance/TreeGridMemory.java
uitest/src/test/java/com/vaadin/tests/components/treegrid/TreeGridBasicFeaturesTest.java
uitest/src/test/java/com/vaadin/tests/components/treegrid/TreeGridClientSortTest.java

index 44b1690e7b80e775f88db579ef45cee25b8b5598..abfda6bf2ebe067a6b7d03ec1464e85228c4df1c 100644 (file)
         
         <li>The <tt>TreeGrid</tt> component replaces <tt>TreeTable</tt> component</li>
         <li>The <tt>Tree</tt> component replaces old <tt>Tree</tt> component</li>
-        <li>The <tt>HierarchicalDataProvider</tt> interface replaces <tt>Container.Hierarchical</tt> and <<tt>InMemoryHierarchicalDataProvider</tt> replaces <tt>HierarchicalContainer</tt></li>
+        <li>The <tt>HierarchicalDataProvider</tt> interface replaces <tt>Container.Hierarchical</tt> and <<tt>TreeDataProvider</tt> replaces <tt>HierarchicalContainer</tt></li>
         <li>The <tt>DragSourceExtension</tt> and <tt>DropTargetExtension</tt> extensions replace the old DnD features</li>
         <li>OSGi bundle manifests of Vaadin Framework JARs no longer export <tt>/VAADIN</tt>, and there are new mechanisms for publishing static resources for OSGi</li>
         <li>Tooltip styles for <tt>ContentMode.PREFORMATTED</tt> have been changed in all built-in themes to use the application font and allow long lines to wrap to multiple lines.</li>
index dd957a0308806ad8d6677505d6ff8d0e52549a19..f81342c5ba2588e20d955d04471a85e87d270f64 100644 (file)
@@ -31,32 +31,32 @@ image::img/tree-basic.png[width=70%, scaledwidth=100%]
 [[components.tree.data]]
 == Binding to Data
 
-[classname]#Tree# is used by binding it to a hierarchical data provider. The data provider can be based on in-memory or back end data. For in-memory data, the [classname]#InMemoryHierarchicalDataProvider# can be used, and for loading data from a back end, you need to implement three methods from the [interfacename]#HierarchicalDataProvider# interface. Usage of both data providers is described in
+[classname]#Tree# is used by binding it to a hierarchical data provider. The data provider can be based on in-memory or back end data. For in-memory data, the [classname]#TreeDataProvider# can be used, and for loading data from a back end, you need to implement three methods from the [interfacename]#HierarchicalDataProvider# interface. Usage of both data providers is described in
 <<dummy/../../../framework/datamodel/datamodel-hierarchical.asciidoc#datamodel.hierarchical,"Hierarchical Data">>.
 
 
-The [classname]#HierarchyData# class can be used to build the hierarchical data structure,
-and it can then be passed on to [classname]#InMemoryHierarchicalDataProvider#. It is simply a hierarchical
+The [classname]#TreeData# class can be used to build the hierarchical data structure,
+and it can then be passed on to [classname]#TreeDataProvider#. It is simply a hierarchical
 collection, that the data provider uses to populate the [classname]#Tree#.
 
 The [methodname]#setItems# method in [classname]#Tree# can be used to set the root level items. Internally
-an [classname]#InMemoryHierarchicalDataProvider# with [classname]#HierarchyData# is used.
+an [classname]#TreeDataProvider# with [classname]#TreeData# is used.
 
 [source, java]
 ----
 // An initial planet tree
 Tree<String> tree = new Tree<>();
-HierarchyData<String> hierarchyData = new HierarchyData<>();
+TreeData<String> treeData = new TreeData<>();
 
 // Couple of childless root items
-hierarchyData.addItem(null,"Mercury");
-hierarchyData.addItem(null,"Venus");
+treeData.addItem(null,"Mercury");
+treeData.addItem(null,"Venus");
 
 // Items with hierarchy
-hierarchyData.addItem(null,"Earth");
-hierarchyData.addItem("Earth","The Moon");
+treeData.addItem(null,"Earth");
+treeData.addItem("Earth","The Moon");
 
-inMemoryDataProvider = new InMemoryHierarchicalDataProvider<>(hierarchyData);
+inMemoryDataProvider = new TreeDataProvider<>(treeData);
 tree.setDataProvider(inMemoryDataProvider);
 tree.expand("Earth"); // Expand programmatically
 ----
@@ -67,9 +67,9 @@ the in-memory data in the tree, you may do it as follows:
 [source, java]
 ----
 // Add Mars with satellites
-hierarchyData.addItem(null, "Mars");
-hierarchyData.addItem("Mars", "Phobos");
-hierarchyData.addItem("Mars", "Deimos");
+treeData.addItem(null, "Mars");
+treeData.addItem("Mars", "Phobos");
+treeData.addItem("Mars", "Deimos");
 inMemoryDataProvider.refreshAll();
 
 ----
@@ -208,4 +208,4 @@ You could thereby define the item styling as follows:
     font-style: italic;
 }
 ----
-////
\ No newline at end of file
+////
index d5659cb556a5a7246c8eb111f0e9a4b71f83fa3c..7f444602d9e17ffdb6226e9ea53a749613ad67da 100644 (file)
@@ -30,7 +30,7 @@ image::img/tree-grid-basic.png[width=70%, scaledwidth=100%]
 [[components.treegrid.data]]
 == Binding to Data
 
-[classname]#TreeGrid# is used by binding it to a hierarchical data provider. The data provider can be based on in-memory or back end data. For in-memory data, the [classname]#InMemoryHierarchicalDataProvider# can be used, and for loading data from a back end, you need to implement three methods from the [interfacename]#HierarchicalDataProvider# interface. Usage of both data providers is described in
+[classname]#TreeGrid# is used by binding it to a hierarchical data provider. The data provider can be based on in-memory or back end data. For in-memory data, the [classname]#TreeDataProvider# can be used, and for loading data from a back end, you need to implement three methods from the [interfacename]#HierarchicalDataProvider# interface. Usage of both data providers is described in
 <<dummy/../../../framework/datamodel/datamodel-hierarchical.asciidoc#datamodel.hierarchical,"Hierarchical Data">>.
 
 Populating a [classname]#TreeGrid# with in-memory data can be done as follows
@@ -39,7 +39,7 @@ Populating a [classname]#TreeGrid# with in-memory data can be done as follows
 ----
 Project rootProject = getRootRroject();
 
-HierarchyData<Project> data = new HierarchyData<>();
+TreeData<Project> data = new TreeData<>();
 // add a root level item with null parent
 data.addItem(null, rootProject);
 
@@ -48,7 +48,7 @@ rootProject.flattened().forEach(
        project -> data.addItems(project, project.getSubProjects()));
 
 TreeGrid<Project> treeGrid = new TreeGrid<>();
-treeGrid.setDataProvider(new InMemoryHierarchicalDataProvider<>(data));
+treeGrid.setDataProvider(new TreeDataProvider<>(data));
 
 // the first column gets the hierarchy indicator by default
 treeGrid.addColumn(Project::getName).setCaption("Project Name");
@@ -56,18 +56,18 @@ treeGrid.addColumn(Project::getHoursDone).setCaption("Hours Done");
 treeGrid.addColumn(Project::getLastModified).setCaption("Last Modified");
 ----
 
-The [classname]#HierarchyData# class can be used to build the hierarchical data structure,
-and it can then be passed on to [classname]#InMemoryHierarchicalDataProvider#. It is simply a hierarchical
+The [classname]#TreeData# class can be used to build the hierarchical data structure,
+and it can then be passed on to [classname]#TreeDataProvider#. It is simply a hierarchical
 collection, that the data provider uses to populate the [classname]#TreeGrid#.
 
 The [methodname]#setItems# method in [classname]#TreeGrid# can be used to set the root level items. Internally
-an [classname]#InMemoryHierarchicalDataProvider# with [classname]#HierarchyData# is used. If at any time you want to modify the in-memory data in the grid, you may do it as follows
+an [classname]#TreeDataProvider# with [classname]#TreeData# is used. If at any time you want to modify the in-memory data in the grid, you may do it as follows
 
 [source, java]
 ----
-InMemoryHierarchicalDataProvider<Project> dataProvider = (InMemoryHierarchicalDataProvider<Project>) treeGrid.getDataProvider();
+TreeDataProvider<Project> dataProvider = (TreeDataProvider<Project>) treeGrid.getDataProvider();
 
-HierarchyData<Project> data = dataProvider.getData();
+TreeData<Project> data = dataProvider.getData();
 // add new items
 data.addItem(null, newProject);
 data.addItems(newProject, newProject.getChildren());
index 735317c519b4a8b44037661bffe799c3cd30f278..f405bc775fa028abf189c763597dc19a329cc051 100644 (file)
@@ -11,21 +11,21 @@ IMPORTANT: The [interfacename]#HierarchicalDataProvider# is currently being deve
 
 The [classname]#Tree# and the [classname]#TreeGrid# components allow you to show data with hierarchical relationships between items.
 That data can be populated by on-demand from a back end by implementing the [interfacename]#HierarchicalDataProvider# interface. If you have the data available in-memory on the server,
-you use the collection style API of [classname]#HierarchyData# and then pass it to a [classname]#InMemoryHierarchicalDataProvider#. This chapter introduces the hierarchical data providers and how they work.
+you use the collection style API of [classname]#TreeData# and then pass it to a [classname]#TreeDataProvider#. This chapter introduces the hierarchical data providers and how they work.
 For using them with the components you should see <<dummy/../../../framework/components/components-tree.asciidoc#components.tree,"Tree">>
 and <<dummy/../../../framework/components/components-treegrid.asciidoc#components.treegrid,"TreeGrid">> documentation.
 
 == In-memory Hierarchical Data
 
-When the hierarchical data is available in the server side memory, you can use it to populate the [classname]#HierarchyData# that is the source of data for an [classname]#InMemoryHierarchicalDataProvider#. It contains collection style API to construct the hierarchical structure of your data, and also verifies that the hierarchy structure is valid.
+When the hierarchical data is available in the server side memory, you can use it to populate the [classname]#TreeData# that is the source of data for an [classname]#TreeDataProvider#. It contains collection style API to construct the hierarchical structure of your data, and also verifies that the hierarchy structure is valid.
 
-The following example populates a [classname]#HierarchyData# with two levels of data:
+The following example populates a [classname]#TreeData# with two levels of data:
 
 [source, java]
 ----
 Collection<Project> projects = service.getProjects();
 
-HierarchyData<Project> data = new HierarchyData<>();
+TreeData<Project> data = new TreeData<>();
 // add root level items
 data.addItems(null, projects);
 
@@ -33,16 +33,16 @@ data.addItems(null, projects);
 projects.forEach(project -> data.addItems(project, project.getChildren()));
 
 // construct the data provider for the hierarchical data we've built
-InMemoryHierarchicalDataProvider<Project> dataProvider = new InMemoryHierarchicalDataProvider<>(data);
+TreeDataProvider<Project> dataProvider = new TreeDataProvider<>(data);
 ----
 
 === Updating data
 
-When adding or removing items from the [classname]#HierarchyData#, you need to always notify the data provider that it should refresh its data. This can be done with the [methodname]#refreshAll# method in the data provider.
+When adding or removing items from the [classname]#TreeData#, you need to always notify the data provider that it should refresh its data. This can be done with the [methodname]#refreshAll# method in the data provider.
 
 [source, java]
 ----
-HierarchyData<Project> data = dataProvider.getHierarchyData();
+TreeData<Project> data = dataProvider.getData();
 data.addItem(null, newProject);
 data.addItems(newProject, newProject.getChildren());
 
@@ -55,14 +55,14 @@ dataProvider.refreshAll();
 
 === Sorting and Filtering
 
-For [classname]#InMemoryHierarchicalDataProvider#, both the sorting and filtering API is the same as in [classname]#ListDataProvider#. Sorting and filtering are applied separately for each hierarchy level, meaning e.g. that for a node that has not passed the filter there are no children shown.
+For [classname]#TreeDataProvider#, both the sorting and filtering API is the same as in [classname]#ListDataProvider#. Sorting and filtering are applied separately for each hierarchy level, meaning e.g. that for a node that has not passed the filter there are no children shown.
 
 [source, java]
 ----
 // setting sorting or filtering automatically refreshes the data
 dataProvider.setSortComparator((projectA, projectB) ->
       projectA.getHours().compareTo(projectB.getHours()));
-      
+
 dataProvider.setFilter(project -> project.getHours() > 100);
 ----
 
@@ -72,7 +72,7 @@ The lazy loading hierarchical data, same concepts apply as with the non-hierarch
 
 To load hierarchical data on-demand from your back end, you should extend the [classname]#AbstractHierarchicalDataProvider# class. Then you just have to implement the following three methods:
 
-* `boolean hasChildren(T item)` 
+* `boolean hasChildren(T item)`
 ** This tells the data provider whether the given item has children and should be expandable. Note that this method is called frequently and should not do any costly operations.
 
 * `int getChildCount(HierarchicalQuery<T, F> query)`
@@ -87,7 +87,7 @@ To load hierarchical data on-demand from your back end, you should extend the [c
 ** The parent node is available in the [classname]#HierarchicalQuery# via the [methodname]#getParent# method, which returns `null` for the root level.
 ** This method is called whenever the data should be displayed in the UI
 
-Note that the [classname]#HierarchicalQuery# query object contains the relevant information regarding the sorting and filtering. 
+Note that the [classname]#HierarchicalQuery# query object contains the relevant information regarding the sorting and filtering.
 
 The following code snippet shows a simple example on how to building a lazy hierarchical data provider based on file system structure:
 
diff --git a/server/src/main/java/com/vaadin/data/HasHierarchicalDataProvider.java b/server/src/main/java/com/vaadin/data/HasHierarchicalDataProvider.java
new file mode 100644 (file)
index 0000000..e43b9d6
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.data;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import com.vaadin.data.provider.DataProvider;
+import com.vaadin.data.provider.HierarchicalDataProvider;
+import com.vaadin.data.provider.TreeDataProvider;
+
+/**
+ * A generic interface for hierarchical listing components that use a data
+ * provider for showing data.
+ *
+ * @author Vaadin Ltd
+ * @since 8.1
+ *
+ * @param <T>
+ *            the item data type
+ */
+public interface HasHierarchicalDataProvider<T> extends HasDataProvider<T> {
+
+    /**
+     * Gets the backing {@link TreeData} instance of the data provider, if the
+     * data provider is a {@link TreeDataProvider}.
+     *
+     * @return the TreeData instance used by the data provider
+     * @throws IllegalStateException
+     *             if the type of the data provider is not
+     *             {@link TreeDataProvider}
+     */
+    @SuppressWarnings("unchecked")
+    public default TreeData<T> getTreeData() {
+        if (getDataProvider() instanceof TreeDataProvider) {
+            return ((TreeDataProvider<T>) getDataProvider()).getTreeData();
+        } else {
+            throw new IllegalStateException("");
+        }
+    }
+
+    /**
+     * Sets the root data items of this component provided as a collection and
+     * recursively populates them with child items with the given value
+     * provider.
+     * <p>
+     * The provided items are wrapped into a {@link TreeDataProvider} backed by
+     * a flat {@link TreeData} structure. The data provider instance is used as
+     * a parameter for the {@link #setDataProvider(DataProvider)} method. It
+     * means that the items collection can be accessed later on via
+     * {@link #getTreeData()}:
+     *
+     * <pre>
+     * <code>
+     * Collection<Person> grandParents = getGrandParents();
+     * HasHierarchicalDataProvider<Person> treeGrid = new TreeGrid<>();
+     * treeGrid.setItems(grandParents, Person::getChildren);
+     * ...
+     *
+     * TreeData<Person> data = treeGrid.getTreeData();
+     * </code>
+     * </pre>
+     * <p>
+     * The returned {@link TreeData} instance may be used as-is to add, remove
+     * or modify items in the hierarchy. These modifications to the object are
+     * not automatically reflected back to the TreeGrid. Items modified should
+     * be refreshed with {@link HierarchicalDataProvider#refreshItem(Object)}
+     * and when adding or removing items
+     * {@link HierarchicalDataProvider#refreshAll()} should be called.
+     *
+     * @param rootItems
+     *            the root items to display, not {@code null}
+     * @param childItemProvider
+     *            the value provider used to recursively populate the given root
+     *            items with child items, not {@code null}
+     */
+    public default void setItems(Collection<T> rootItems,
+            ValueProvider<T, Collection<T>> childItemProvider) {
+        Objects.requireNonNull(rootItems, "Given root items may not be null");
+        Objects.requireNonNull(childItemProvider,
+                "Given child item provider may not be null");
+        setDataProvider(new TreeDataProvider<>(
+                new TreeData<T>().addItems(rootItems, childItemProvider)));
+    }
+
+    /**
+     * Sets the data items of this component provided as a collection.
+     * <p>
+     * The provided items are wrapped into a {@link TreeDataProvider} backed by
+     * a flat {@link TreeData} structure. The data provider instance is used as
+     * a parameter for the {@link #setDataProvider(DataProvider)} method. It
+     * means that the items collection can be accessed later on via
+     * {@link #getTreeData()}:
+     *
+     * <pre>
+     * <code>
+     * HasHierarchicalDataProvider<String> treeGrid = new TreeGrid<>();
+     * treeGrid.setItems(Arrays.asList("a","b"));
+     * ...
+     *
+     * TreeData<String> data = treeGrid.getTreeData();
+     * </code>
+     * </pre>
+     * <p>
+     * The returned {@link TreeData} instance may be used as-is to add, remove
+     * or modify items in the hierarchy. These modifications to the object are
+     * not automatically reflected back to the TreeGrid. Items modified should
+     * be refreshed with {@link HierarchicalDataProvider#refreshItem(Object)}
+     * and when adding or removing items
+     * {@link HierarchicalDataProvider#refreshAll()} should be called.
+     *
+     * @param items
+     *            the data items to display, not {@code null}
+     */
+    @Override
+    public default void setItems(Collection<T> items) {
+        Objects.requireNonNull(items, "Given collection may not be null");
+        setDataProvider(new TreeDataProvider<>(
+                new TreeData<T>().addItems(null, items)));
+    }
+
+    /**
+     * Sets the data items of this component provided as a stream.
+     * <p>
+     * The provided items are wrapped into a {@link TreeDataProvider} backed by
+     * a flat {@link TreeData} structure. The data provider instance is used as
+     * a parameter for the {@link #setDataProvider(DataProvider)} method. It
+     * means that the items collection can be accessed later on via
+     * {@link #getTreeData()}:
+     *
+     * <pre>
+     * <code>
+     * HasHierarchicalDataProvider<String> treeGrid = new TreeGrid<>();
+     * treeGrid.setItems(Stream.of("a","b"));
+     * ...
+     *
+     * TreeData<String> data = treeGrid.getTreeData();
+     * </code>
+     * </pre>
+     * <p>
+     * The returned {@link TreeData} instance may be used as-is to add, remove
+     * or modify items in the hierarchy. These modifications to the object are
+     * not automatically reflected back to the TreeGrid. Items modified should
+     * be refreshed with {@link HierarchicalDataProvider#refreshItem(Object)}
+     * and when adding or removing items
+     * {@link HierarchicalDataProvider#refreshAll()} should be called.
+     *
+     * @param items
+     *            the data items to display, not {@code null}
+     */
+    @Override
+    public default void setItems(Stream<T> items) {
+        Objects.requireNonNull(items, "Given stream may not be null");
+        setItems(items.collect(Collectors.toList()));
+    }
+
+    /**
+     * Sets the data items of this listing.
+     * <p>
+     * The provided items are wrapped into a {@link TreeDataProvider} backed by
+     * a flat {@link TreeData} structure. The data provider instance is used as
+     * a parameter for the {@link #setDataProvider(DataProvider)} method. It
+     * means that the items collection can be accessed later on via
+     * {@link #getTreeData()}:
+     *
+     * <pre>
+     * <code>
+     * TreeGrid<String> treeGrid = new TreeGrid<>();
+     * treeGrid.setItems("a","b");
+     * ...
+     *
+     * TreeData<String> data = treeGrid.getTreeData();
+     * </code>
+     * </pre>
+     * <p>
+     * The returned {@link TreeData} instance may be used as-is to add, remove
+     * or modify items in the hierarchy. These modifications to the object are
+     * not automatically reflected back to the TreeGrid. Items modified should
+     * be refreshed with {@link HierarchicalDataProvider#refreshItem(Object)}
+     * and when adding or removing items
+     * {@link HierarchicalDataProvider#refreshAll()} should be called.
+     *
+     * @param items
+     *            the data items to display, not {@code null}
+     */
+    @Override
+    public default void setItems(@SuppressWarnings("unchecked") T... items) {
+        Objects.requireNonNull(items, "Given items may not be null");
+        setItems(Arrays.asList(items));
+    }
+}
diff --git a/server/src/main/java/com/vaadin/data/HierarchyData.java b/server/src/main/java/com/vaadin/data/HierarchyData.java
deleted file mode 100644 (file)
index 0cf680d..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright 2000-2016 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.vaadin.data;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.stream.Stream;
-
-/**
- * Class for representing hierarchical data.
- *
- * @author Vaadin Ltd
- * @since 8.1
- *
- * @param <T>
- *            data type
- */
-public class HierarchyData<T> implements Serializable {
-
-    private static class HierarchyWrapper<T> implements Serializable {
-        private T item;
-        private T parent;
-        private List<T> children;
-
-        public HierarchyWrapper(T item, T parent) {
-            this.item = item;
-            this.parent = parent;
-            children = new ArrayList<>();
-        }
-
-        public T getItem() {
-            return item;
-        }
-
-        public void setItem(T item) {
-            this.item = item;
-        }
-
-        public T getParent() {
-            return parent;
-        }
-
-        public void setParent(T parent) {
-            this.parent = parent;
-        }
-
-        public List<T> getChildren() {
-            return children;
-        }
-
-        public void setChildren(List<T> children) {
-            this.children = children;
-        }
-
-        public void addChild(T child) {
-            children.add(child);
-        }
-
-        public void removeChild(T child) {
-            children.remove(child);
-        }
-    }
-
-    private final Map<T, HierarchyWrapper<T>> itemToWrapperMap;
-
-    /**
-     * Creates an initially empty hierarchical data representation to which
-     * items can be added or removed.
-     */
-    public HierarchyData() {
-        itemToWrapperMap = new LinkedHashMap<>();
-        itemToWrapperMap.put(null, new HierarchyWrapper<>(null, null));
-    }
-
-    /**
-     * Adds a data item as a child of {@code parent}. Call with {@code null} as
-     * parent to add a root level item. The given parent item must already exist
-     * in this structure, and an item can only be added to this structure once.
-     *
-     * @param parent
-     *            the parent item for which the items are added as children
-     * @param item
-     *            the item to add
-     * @return this
-     *
-     * @throws IllegalArgumentException
-     *             if parent is not null and not already added to this structure
-     * @throws IllegalArgumentException
-     *             if the item has already been added to this structure
-     * @throws NullPointerException
-     *             if item is null
-     */
-    public HierarchyData<T> addItem(T parent, T item) {
-        Objects.requireNonNull(item, "Item cannot be null");
-        if (parent != null && !contains(parent)) {
-            throw new IllegalArgumentException(
-                    "Parent needs to be added before children. "
-                            + "To add root items, call with parent as null");
-        }
-        if (contains(item)) {
-            throw new IllegalArgumentException(
-                    "Cannot add the same item multiple times: " + item);
-        }
-        putItem(item, parent);
-        return this;
-    }
-
-    /**
-     * Adds a list of data items as children of {@code parent}. Call with
-     * {@code null} as parent to add root level items. The given parent item
-     * must already exist in this structure, and an item can only be added to
-     * this structure once.
-     *
-     * @param parent
-     *            the parent item for which the items are added as children
-     * @param items
-     *            the list of items to add
-     * @return this
-     *
-     * @throws IllegalArgumentException
-     *             if parent is not null and not already added to this structure
-     * @throws IllegalArgumentException
-     *             if any of the given items have already been added to this
-     *             structure
-     * @throws NullPointerException
-     *             if any of the items are null
-     */
-    public HierarchyData<T> addItems(T parent,
-            @SuppressWarnings("unchecked") T... items) {
-        Arrays.asList(items).stream().forEach(item -> addItem(parent, item));
-        return this;
-    }
-
-    /**
-     * Adds a list of data items as children of {@code parent}. Call with
-     * {@code null} as parent to add root level items. The given parent item
-     * must already exist in this structure, and an item can only be added to
-     * this structure once.
-     *
-     * @param parent
-     *            the parent item for which the items are added as children
-     * @param items
-     *            the collection of items to add
-     * @return this
-     *
-     * @throws IllegalArgumentException
-     *             if parent is not null and not already added to this structure
-     * @throws IllegalArgumentException
-     *             if any of the given items have already been added to this
-     *             structure
-     * @throws NullPointerException
-     *             if any of the items are null
-     */
-    public HierarchyData<T> addItems(T parent, Collection<T> items) {
-        items.stream().forEach(item -> addItem(parent, item));
-        return this;
-    }
-
-    /**
-     * Adds data items contained in a stream as children of {@code parent}. Call
-     * with {@code null} as parent to add root level items. The given parent
-     * item must already exist in this structure, and an item can only be added
-     * to this structure once.
-     *
-     * @param parent
-     *            the parent item for which the items are added as children
-     * @param items
-     *            stream of items to add
-     * @return this
-     *
-     * @throws IllegalArgumentException
-     *             if parent is not null and not already added to this structure
-     * @throws IllegalArgumentException
-     *             if any of the given items have already been added to this
-     *             structure
-     * @throws NullPointerException
-     *             if any of the items are null
-     */
-    public HierarchyData<T> addItems(T parent, Stream<T> items) {
-        items.forEach(item -> addItem(parent, item));
-        return this;
-    }
-
-    /**
-     * Remove a given item from this structure. Additionally, this will
-     * recursively remove any descendants of the item.
-     *
-     * @param item
-     *            the item to remove, or null to clear all data
-     * @return this
-     *
-     * @throws IllegalArgumentException
-     *             if the item does not exist in this structure
-     */
-    public HierarchyData<T> removeItem(T item) {
-        if (!contains(item)) {
-            throw new IllegalArgumentException(
-                    "Item '" + item + "' not in the hierarchy");
-        }
-        new ArrayList<>(getChildren(item)).forEach(child -> removeItem(child));
-        itemToWrapperMap.get(itemToWrapperMap.get(item).getParent())
-                .removeChild(item);
-        if (item != null) {
-            // remove non root item from backing map
-            itemToWrapperMap.remove(item);
-        }
-        return this;
-    }
-
-    /**
-     * Clear all items from this structure. Shorthand for calling
-     * {@link #removeItem(Object)} with null.
-     *
-     * @return this
-     */
-    public HierarchyData<T> clear() {
-        removeItem(null);
-        return this;
-    }
-
-    /**
-     * Get the immediate child items for the given item.
-     *
-     * @param item
-     *            the item for which to retrieve child items for, null to
-     *            retrieve all root items
-     * @return a list of child items for the given item
-     *
-     * @throws IllegalArgumentException
-     *             if the item does not exist in this structure
-     */
-    public List<T> getChildren(T item) {
-        if (!contains(item)) {
-            throw new IllegalArgumentException(
-                    "Item '" + item + "' not in the hierarchy");
-        }
-        return itemToWrapperMap.get(item).getChildren();
-    }
-
-    /**
-     * Check whether the given item is in this hierarchy.
-     *
-     * @param item
-     *            the item to check
-     * @return {@code true} if the item is in this hierarchy, {@code false} if
-     *         not
-     */
-    public boolean contains(T item) {
-        return itemToWrapperMap.containsKey(item);
-    }
-
-    private void putItem(T item, T parent) {
-        HierarchyWrapper<T> wrappedItem = new HierarchyWrapper<>(item, parent);
-        if (itemToWrapperMap.containsKey(parent)) {
-            itemToWrapperMap.get(parent).addChild(item);
-        }
-        itemToWrapperMap.put(item, wrappedItem);
-    }
-}
diff --git a/server/src/main/java/com/vaadin/data/TreeData.java b/server/src/main/java/com/vaadin/data/TreeData.java
new file mode 100644 (file)
index 0000000..def6974
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.data;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Stream;
+
+/**
+ * Class for representing hierarchical data.
+ *
+ * @author Vaadin Ltd
+ * @since 8.1
+ *
+ * @param <T>
+ *            data type
+ */
+public class TreeData<T> implements Serializable {
+
+    private static class HierarchyWrapper<T> implements Serializable {
+        private T item;
+        private T parent;
+        private List<T> children;
+
+        public HierarchyWrapper(T item, T parent) {
+            this.item = item;
+            this.parent = parent;
+            children = new ArrayList<>();
+        }
+
+        public T getItem() {
+            return item;
+        }
+
+        public void setItem(T item) {
+            this.item = item;
+        }
+
+        public T getParent() {
+            return parent;
+        }
+
+        public void setParent(T parent) {
+            this.parent = parent;
+        }
+
+        public List<T> getChildren() {
+            return children;
+        }
+
+        public void setChildren(List<T> children) {
+            this.children = children;
+        }
+
+        public void addChild(T child) {
+            children.add(child);
+        }
+
+        public void removeChild(T child) {
+            children.remove(child);
+        }
+    }
+
+    private final Map<T, HierarchyWrapper<T>> itemToWrapperMap;
+
+    /**
+     * Creates an initially empty hierarchical data representation to which
+     * items can be added or removed.
+     */
+    public TreeData() {
+        itemToWrapperMap = new LinkedHashMap<>();
+        itemToWrapperMap.put(null, new HierarchyWrapper<>(null, null));
+    }
+
+    /**
+     * Adds a data item as a child of {@code parent}. Call with {@code null} as
+     * parent to add a root level item. The given parent item must already exist
+     * in this structure, and an item can only be added to this structure once.
+     *
+     * @param parent
+     *            the parent item for which the items are added as children
+     * @param item
+     *            the item to add
+     * @return this
+     *
+     * @throws IllegalArgumentException
+     *             if parent is not null and not already added to this structure
+     * @throws IllegalArgumentException
+     *             if the item has already been added to this structure
+     * @throws NullPointerException
+     *             if item is null
+     */
+    public TreeData<T> addItem(T parent, T item) {
+        Objects.requireNonNull(item, "Item cannot be null");
+        if (parent != null && !contains(parent)) {
+            throw new IllegalArgumentException(
+                    "Parent needs to be added before children. "
+                            + "To add root items, call with parent as null");
+        }
+        if (contains(item)) {
+            throw new IllegalArgumentException(
+                    "Cannot add the same item multiple times: " + item);
+        }
+        putItem(item, parent);
+        return this;
+    }
+
+    /**
+     * Adds a list of data items as children of {@code parent}. Call with
+     * {@code null} as parent to add root level items. The given parent item
+     * must already exist in this structure, and an item can only be added to
+     * this structure once.
+     *
+     * @param parent
+     *            the parent item for which the items are added as children
+     * @param items
+     *            the list of items to add
+     * @return this
+     *
+     * @throws IllegalArgumentException
+     *             if parent is not null and not already added to this structure
+     * @throws IllegalArgumentException
+     *             if any of the given items have already been added to this
+     *             structure
+     * @throws NullPointerException
+     *             if any of the items are null
+     */
+    public TreeData<T> addItems(T parent,
+            @SuppressWarnings("unchecked") T... items) {
+        Arrays.asList(items).stream().forEach(item -> addItem(parent, item));
+        return this;
+    }
+
+    /**
+     * Adds a list of data items as children of {@code parent}. Call with
+     * {@code null} as parent to add root level items. The given parent item
+     * must already exist in this structure, and an item can only be added to
+     * this structure once.
+     *
+     * @param parent
+     *            the parent item for which the items are added as children
+     * @param items
+     *            the collection of items to add
+     * @return this
+     *
+     * @throws IllegalArgumentException
+     *             if parent is not null and not already added to this structure
+     * @throws IllegalArgumentException
+     *             if any of the given items have already been added to this
+     *             structure
+     * @throws NullPointerException
+     *             if any of the items are null
+     */
+    public TreeData<T> addItems(T parent, Collection<T> items) {
+        items.stream().forEach(item -> addItem(parent, item));
+        return this;
+    }
+
+    /**
+     * Adds data items contained in a stream as children of {@code parent}. Call
+     * with {@code null} as parent to add root level items. The given parent
+     * item must already exist in this structure, and an item can only be added
+     * to this structure once.
+     *
+     * @param parent
+     *            the parent item for which the items are added as children
+     * @param items
+     *            stream of items to add
+     * @return this
+     *
+     * @throws IllegalArgumentException
+     *             if parent is not null and not already added to this structure
+     * @throws IllegalArgumentException
+     *             if any of the given items have already been added to this
+     *             structure
+     * @throws NullPointerException
+     *             if any of the items are null
+     */
+    public TreeData<T> addItems(T parent, Stream<T> items) {
+        items.forEach(item -> addItem(parent, item));
+        return this;
+    }
+
+    /**
+     * Adds the given items as root items and uses the given value provider to
+     * recursively populate children of the root items.
+     * 
+     * @param rootItems
+     *            the root items to add
+     * @param childItemProvider
+     *            the value provider used to recursively populate this TreeData
+     *            from the given root items
+     * @return this
+     */
+    public TreeData<T> addItems(Collection<T> rootItems,
+            ValueProvider<T, Collection<T>> childItemProvider) {
+        rootItems.forEach(item -> {
+            addItem(null, item);
+            Collection<T> childItems = childItemProvider.apply(item);
+            addItems(item, childItems);
+            addItemsRecursively(childItems, childItemProvider);
+        });
+        return this;
+    }
+
+    /**
+     * Remove a given item from this structure. Additionally, this will
+     * recursively remove any descendants of the item.
+     *
+     * @param item
+     *            the item to remove, or null to clear all data
+     * @return this
+     *
+     * @throws IllegalArgumentException
+     *             if the item does not exist in this structure
+     */
+    public TreeData<T> removeItem(T item) {
+        if (!contains(item)) {
+            throw new IllegalArgumentException(
+                    "Item '" + item + "' not in the hierarchy");
+        }
+        new ArrayList<>(getChildren(item)).forEach(child -> removeItem(child));
+        itemToWrapperMap.get(itemToWrapperMap.get(item).getParent())
+                .removeChild(item);
+        if (item != null) {
+            // remove non root item from backing map
+            itemToWrapperMap.remove(item);
+        }
+        return this;
+    }
+
+    /**
+     * Clear all items from this structure. Shorthand for calling
+     * {@link #removeItem(Object)} with null.
+     *
+     * @return this
+     */
+    public TreeData<T> clear() {
+        removeItem(null);
+        return this;
+    }
+
+    /**
+     * Get the immediate child items for the given item.
+     *
+     * @param item
+     *            the item for which to retrieve child items for, null to
+     *            retrieve all root items
+     * @return a list of child items for the given item
+     *
+     * @throws IllegalArgumentException
+     *             if the item does not exist in this structure
+     */
+    public List<T> getChildren(T item) {
+        if (!contains(item)) {
+            throw new IllegalArgumentException(
+                    "Item '" + item + "' not in the hierarchy");
+        }
+        return itemToWrapperMap.get(item).getChildren();
+    }
+
+    /**
+     * Check whether the given item is in this hierarchy.
+     *
+     * @param item
+     *            the item to check
+     * @return {@code true} if the item is in this hierarchy, {@code false} if
+     *         not
+     */
+    public boolean contains(T item) {
+        return itemToWrapperMap.containsKey(item);
+    }
+
+    private void putItem(T item, T parent) {
+        HierarchyWrapper<T> wrappedItem = new HierarchyWrapper<>(item, parent);
+        if (itemToWrapperMap.containsKey(parent)) {
+            itemToWrapperMap.get(parent).addChild(item);
+        }
+        itemToWrapperMap.put(item, wrappedItem);
+    }
+
+    private void addItemsRecursively(Collection<T> items,
+            ValueProvider<T, Collection<T>> childItemProvider) {
+        items.forEach(item -> {
+            Collection<T> childItems = childItemProvider.apply(item);
+            addItems(item, childItems);
+            addItemsRecursively(childItems, childItemProvider);
+        });
+    }
+}
index 5d3bd81a0535db46ca60c0c85aa377a5b42bc83b..4a8ae62772b3e590560c5b7c501cdb91eb56dfaf 100644 (file)
@@ -27,7 +27,7 @@ import java.util.logging.Logger;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import com.vaadin.data.HierarchyData;
+import com.vaadin.data.TreeData;
 import com.vaadin.data.provider.HierarchyMapper.TreeLevelQuery;
 import com.vaadin.data.provider.HierarchyMapper.TreeNode;
 import com.vaadin.server.SerializableConsumer;
@@ -75,12 +75,12 @@ public class HierarchicalDataCommunicator<T> extends DataCommunicator<T> {
 
     /**
      * Construct a new hierarchical data communicator backed by a
-     * {@link InMemoryHierarchicalDataProvider}.
+     * {@link TreeDataProvider}.
      */
     public HierarchicalDataCommunicator() {
         super();
-        dataProvider = new InMemoryHierarchicalDataProvider<>(
-                new HierarchyData<>());
+        dataProvider = new TreeDataProvider<>(
+                new TreeData<>());
     }
 
     @Override
diff --git a/server/src/main/java/com/vaadin/data/provider/InMemoryDataProvider.java b/server/src/main/java/com/vaadin/data/provider/InMemoryDataProvider.java
new file mode 100644 (file)
index 0000000..bfb62b8
--- /dev/null
@@ -0,0 +1,451 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.data.provider;
+
+import java.util.Locale;
+import java.util.Objects;
+
+import com.vaadin.data.ValueProvider;
+import com.vaadin.server.SerializableBiPredicate;
+import com.vaadin.server.SerializableComparator;
+import com.vaadin.server.SerializablePredicate;
+import com.vaadin.shared.data.sort.SortDirection;
+import com.vaadin.ui.UI;
+
+/**
+ * A mixin interface for in-memory data providers. Contains methods for
+ * configuring sorting and filtering.
+ *
+ * @author Vaadin Ltd
+ * @since 8.1
+ *
+ * @param <T>
+ *            data type
+ */
+public interface InMemoryDataProvider<T> extends
+        ConfigurableFilterDataProvider<T, SerializablePredicate<T>, SerializablePredicate<T>> {
+
+    @Override
+    public default boolean isInMemory() {
+        return true;
+    }
+
+    /**
+     * Gets the current filter of this data provider.
+     *
+     * @return the filter of this data provider
+     */
+    public SerializablePredicate<T> getFilter();
+
+    /**
+     * Sets a filter to be applied to all queries. The filter replaces any
+     * filter that has been set or added previously.
+     *
+     * @see #setFilter(ValueProvider, SerializablePredicate)
+     * @see #setFilterByValue(ValueProvider, Object)
+     * @see #addFilter(SerializablePredicate)
+     *
+     * @param filter
+     *            the filter to set, or <code>null</code> to remove any set
+     *            filters
+     */
+    @Override
+    public void setFilter(SerializablePredicate<T> filter);
+
+    /**
+     * Sets a filter for an item property. The filter replaces any filter that
+     * has been set or added previously.
+     *
+     * @see #setFilter(SerializablePredicate)
+     * @see #setFilterByValue(ValueProvider, Object)
+     * @see #addFilter(ValueProvider, SerializablePredicate)
+     *
+     * @param valueProvider
+     *            value provider that gets the property value, not
+     *            <code>null</code>
+     * @param valueFilter
+     *            filter for testing the property value, not <code>null</code>
+     */
+    public default <V> void setFilter(ValueProvider<T, V> valueProvider,
+            SerializablePredicate<V> valueFilter) {
+        setFilter(InMemoryDataProviderHelpers
+                .createValueProviderFilter(valueProvider, valueFilter));
+    }
+
+    /**
+     * Adds a filter to be applied to all queries. The filter will be used in
+     * addition to any filter that has been set or added previously.
+     *
+     * @see #addFilter(ValueProvider, SerializablePredicate)
+     * @see #addFilterByValue(ValueProvider, Object)
+     * @see #setFilter(SerializablePredicate)
+     *
+     * @param filter
+     *            the filter to add, not <code>null</code>
+     */
+    public default void addFilter(SerializablePredicate<T> filter) {
+        Objects.requireNonNull(filter, "Filter cannot be null");
+
+        if (getFilter() == null) {
+            setFilter(filter);
+        } else {
+            SerializablePredicate<T> oldFilter = getFilter();
+            setFilter(item -> oldFilter.test(item) && filter.test(item));
+        }
+    }
+
+    /**
+     * Adds a filter for an item property. The filter will be used in addition
+     * to any filter that has been set or added previously.
+     *
+     * @see #addFilter(SerializablePredicate)
+     * @see #addFilterByValue(ValueProvider, Object)
+     * @see #setFilter(ValueProvider, SerializablePredicate)
+     *
+     * @param valueProvider
+     *            value provider that gets the property value, not
+     *            <code>null</code>
+     * @param valueFilter
+     *            filter for testing the property value, not <code>null</code>
+     */
+    public default <V> void addFilter(ValueProvider<T, V> valueProvider,
+            SerializablePredicate<V> valueFilter) {
+        Objects.requireNonNull(valueProvider, "Value provider cannot be null");
+        Objects.requireNonNull(valueFilter, "Value filter cannot be null");
+
+        addFilter(InMemoryDataProviderHelpers
+                .createValueProviderFilter(valueProvider, valueFilter));
+    }
+
+    /**
+     * Sets a filter that requires an item property to have a specific value.
+     * The property value and the provided value are compared using
+     * {@link Object#equals(Object)}. The filter replaces any filter that has
+     * been set or added previously.
+     *
+     * @see #setFilter(SerializablePredicate)
+     * @see #setFilter(ValueProvider, SerializablePredicate)
+     * @see #addFilterByValue(ValueProvider, Object)
+     *
+     * @param valueProvider
+     *            value provider that gets the property value, not
+     *            <code>null</code>
+     * @param requiredValue
+     *            the value that the property must have for the filter to pass
+     */
+    public default <V> void setFilterByValue(ValueProvider<T, V> valueProvider,
+            V requiredValue) {
+        setFilter(InMemoryDataProviderHelpers.createEqualsFilter(valueProvider,
+                requiredValue));
+    }
+
+    /**
+     * Adds a filter that requires an item property to have a specific value.
+     * The property value and the provided value are compared using
+     * {@link Object#equals(Object)}.The filter will be used in addition to any
+     * filter that has been set or added previously.
+     *
+     * @see #setFilterByValue(ValueProvider, Object)
+     * @see #addFilter(SerializablePredicate)
+     * @see #addFilter(ValueProvider, SerializablePredicate)
+     *
+     * @param valueProvider
+     *            value provider that gets the property value, not
+     *            <code>null</code>
+     * @param requiredValue
+     *            the value that the property must have for the filter to pass
+     */
+    public default <V> void addFilterByValue(ValueProvider<T, V> valueProvider,
+            V requiredValue) {
+        addFilter(InMemoryDataProviderHelpers.createEqualsFilter(valueProvider,
+                requiredValue));
+    }
+
+    /**
+     * Removes any filter that has been set or added previously.
+     *
+     * @see #setFilter(SerializablePredicate)
+     */
+    public default void clearFilters() {
+        setFilter(null);
+    }
+
+    /**
+     * Gets the current sort comparator of this data provider.
+     *
+     * @return the sort comparator of this data provider
+     */
+    public SerializableComparator<T> getSortComparator();
+
+    /**
+     * Sets the comparator to use as the default sorting for this data provider.
+     * This overrides the sorting set by any other method that manipulates the
+     * default sorting of this data provider.
+     * <p>
+     * The default sorting is used if the query defines no sorting. The default
+     * sorting is also used to determine the ordering of items that are
+     * considered equal by the sorting defined in the query.
+     *
+     * @see #setSortOrder(ValueProvider, SortDirection)
+     * @see #addSortComparator(SerializableComparator)
+     *
+     * @param comparator
+     *            a comparator to use, or <code>null</code> to clear any
+     *            previously set sort order
+     */
+    public void setSortComparator(SerializableComparator<T> comparator);
+
+    /**
+     * Adds a comparator to the default sorting for this data provider. If no
+     * default sorting has been defined, then the provided comparator will be
+     * used as the default sorting. If a default sorting has been defined, then
+     * the provided comparator will be used to determine the ordering of items
+     * that are considered equal by the previously defined default sorting.
+     * <p>
+     * The default sorting is used if the query defines no sorting. The default
+     * sorting is also used to determine the ordering of items that are
+     * considered equal by the sorting defined in the query.
+     *
+     * @see #setSortComparator(SerializableComparator)
+     * @see #addSortOrder(ValueProvider, SortDirection)
+     *
+     * @param comparator
+     *            a comparator to add, not <code>null</code>
+     */
+    public default void addSortComparator(
+            SerializableComparator<T> comparator) {
+        Objects.requireNonNull(comparator, "Comparator to add cannot be null");
+        SerializableComparator<T> originalComparator = getSortComparator();
+        if (originalComparator == null) {
+            setSortComparator(comparator);
+        } else {
+            setSortComparator((a, b) -> {
+                int result = originalComparator.compare(a, b);
+                if (result == 0) {
+                    result = comparator.compare(a, b);
+                }
+                return result;
+            });
+        }
+    }
+
+    /**
+     * Sets the property and direction to use as the default sorting for this
+     * data provider. This overrides the sorting set by any other method that
+     * manipulates the default sorting of this data provider.
+     * <p>
+     * The default sorting is used if the query defines no sorting. The default
+     * sorting is also used to determine the ordering of items that are
+     * considered equal by the sorting defined in the query.
+     *
+     * @see #setSortComparator(SerializableComparator)
+     * @see #addSortOrder(ValueProvider, SortDirection)
+     *
+     * @param valueProvider
+     *            the value provider that defines the property do sort by, not
+     *            <code>null</code>
+     * @param sortDirection
+     *            the sort direction to use, not <code>null</code>
+     */
+    public default <V extends Comparable<? super V>> void setSortOrder(
+            ValueProvider<T, V> valueProvider, SortDirection sortDirection) {
+        setSortComparator(InMemoryDataProviderHelpers
+                .propertyComparator(valueProvider, sortDirection));
+    }
+
+    /**
+     * Adds a property and direction to the default sorting for this data
+     * provider. If no default sorting has been defined, then the provided sort
+     * order will be used as the default sorting. If a default sorting has been
+     * defined, then the provided sort order will be used to determine the
+     * ordering of items that are considered equal by the previously defined
+     * default sorting.
+     * <p>
+     * The default sorting is used if the query defines no sorting. The default
+     * sorting is also used to determine the ordering of items that are
+     * considered equal by the sorting defined in the query.
+     *
+     * @see #setSortOrder(ValueProvider, SortDirection)
+     * @see #addSortComparator(SerializableComparator)
+     *
+     * @param valueProvider
+     *            the value provider that defines the property do sort by, not
+     *            <code>null</code>
+     * @param sortDirection
+     *            the sort direction to use, not <code>null</code>
+     */
+    public default <V extends Comparable<? super V>> void addSortOrder(
+            ValueProvider<T, V> valueProvider, SortDirection sortDirection) {
+        addSortComparator(InMemoryDataProviderHelpers
+                .propertyComparator(valueProvider, sortDirection));
+    }
+
+    /**
+     * Wraps this data provider to create a new data provider that is filtered
+     * by comparing an item to the filter value provided in the query.
+     * <p>
+     * The predicate receives the item as the first parameter and the query
+     * filter value as the second parameter, and should return <code>true</code>
+     * if the corresponding item should be included. The query filter value is
+     * never <code>null</code> – all items are included without running the
+     * predicate if the query doesn't define any filter.
+     *
+     * @param predicate
+     *            a predicate to use for comparing the item to the query filter,
+     *            not <code>null</code>
+     *
+     * @return a data provider that filters accordingly, not <code>null</code>
+     */
+    public default <Q> DataProvider<T, Q> filteringBy(
+            SerializableBiPredicate<T, Q> predicate) {
+        Objects.requireNonNull(predicate, "Predicate cannot be null");
+
+        return withConvertedFilter(
+                filterValue -> item -> predicate.test(item, filterValue));
+    }
+
+    /**
+     * Wraps this data provider to create a new data provider that is filtered
+     * by comparing an item property value to the filter value provided in the
+     * query.
+     * <p>
+     * The predicate receives the property value as the first parameter and the
+     * query filter value as the second parameter, and should return
+     * <code>true</code> if the corresponding item should be included. The query
+     * filter value is never <code>null</code> – all items are included without
+     * running either callback if the query doesn't define any filter.
+     *
+     * @param valueProvider
+     *            a value provider that gets the property value, not
+     *            <code>null</code>
+     * @param predicate
+     *            a predicate to use for comparing the property value to the
+     *            query filter, not <code>null</code>
+     *
+     * @return a data provider that filters accordingly, not <code>null</code>
+     */
+    public default <V, Q> DataProvider<T, Q> filteringBy(
+            ValueProvider<T, V> valueProvider,
+            SerializableBiPredicate<V, Q> predicate) {
+        Objects.requireNonNull(valueProvider, "Value provider cannot be null");
+        Objects.requireNonNull(predicate, "Predicate cannot be null");
+
+        return filteringBy((item, filterValue) -> predicate
+                .test(valueProvider.apply(item), filterValue));
+    }
+
+    /**
+     * Wraps this data provider to create a new data provider that is filtered
+     * by testing whether the value of a property is equals to the filter value
+     * provided in the query. Equality is tested using
+     * {@link Objects#equals(Object, Object)}.
+     *
+     * @param valueProvider
+     *            a value provider that gets the property value, not
+     *            <code>null</code>
+     *
+     * @return a data provider that filters accordingly, not <code>null</code>
+     */
+    public default <V> DataProvider<T, V> filteringByEquals(
+            ValueProvider<T, V> valueProvider) {
+        return filteringBy(valueProvider, Objects::equals);
+    }
+
+    /**
+     * Wraps this data provider to create a new data provider that is filtered
+     * by a string by checking whether the lower case representation of the
+     * filter value provided in the query is a substring of the lower case
+     * representation of an item property value. The filter never passes if the
+     * item property value is <code>null</code>.
+     *
+     * @param valueProvider
+     *            a value provider that gets the string property value, not
+     *            <code>null</code>
+     * @param locale
+     *            the locale to use for converting the strings to lower case,
+     *            not <code>null</code>
+     * @return a data provider that filters accordingly, not <code>null</code>
+     */
+    public default DataProvider<T, String> filteringBySubstring(
+            ValueProvider<T, String> valueProvider, Locale locale) {
+        Objects.requireNonNull(locale, "Locale cannot be null");
+        return InMemoryDataProviderHelpers.filteringByCaseInsensitiveString(
+                this, valueProvider,
+                String::contains, () -> locale);
+    }
+
+    /**
+     * Wraps this data provider to create a new data provider that is filtered
+     * by a string by checking whether the lower case representation of the
+     * filter value provided in the query is a substring of the lower case
+     * representation of an item property value. Conversion to lower case is
+     * done using the locale of the {@link UI#getCurrent() current UI} if
+     * available, or otherwise {@link Locale#getDefault() the default locale}.
+     * The filter never passes if the item property value is <code>null</code>.
+     *
+     * @param valueProvider
+     *            a value provider that gets the string property value, not
+     *            <code>null</code>
+     * @return a data provider that filters accordingly, not <code>null</code>
+     */
+    public default DataProvider<T, String> filteringBySubstring(
+            ValueProvider<T, String> valueProvider) {
+        return InMemoryDataProviderHelpers.filteringByCaseInsensitiveString(
+                this, valueProvider, String::contains,
+                InMemoryDataProviderHelpers.CURRENT_LOCALE_SUPPLIER);
+    }
+
+    /**
+     * Wraps this data provider to create a new data provider that is filtered
+     * by a string by checking whether the lower case representation of an item
+     * property value starts with the lower case representation of the filter
+     * value provided in the query. The filter never passes if the item property
+     * value is <code>null</code>.
+     *
+     * @param valueProvider
+     *            a value provider that gets the string property value, not
+     *            <code>null</code>
+     * @param locale
+     *            the locale to use for converting the strings to lower case,
+     *            not <code>null</code>
+     * @return a data provider that filters accordingly, not <code>null</code>
+     */
+    public default DataProvider<T, String> filteringByPrefix(
+            ValueProvider<T, String> valueProvider, Locale locale) {
+        return InMemoryDataProviderHelpers.filteringByCaseInsensitiveString(this, valueProvider,
+                String::startsWith, () -> locale);
+    }
+
+    /**
+     * Wraps this data provider to create a new data provider that is filtered
+     * by a string by checking whether the lower case representation of an item
+     * property value starts with the lower case representation of the filter
+     * value provided in the query. Conversion to lower case is done using the
+     * locale of the {@link UI#getCurrent() current UI} if available, or
+     * otherwise {@link Locale#getDefault() the default locale}. The filter
+     * never passes if the item property value is <code>null</code>.
+     *
+     * @param valueProvider
+     *            a value provider that gets the string property value, not
+     *            <code>null</code>
+     * @return a data provider that filters accordingly, not <code>null</code>
+     */
+    public default DataProvider<T, String> filteringByPrefix(
+            ValueProvider<T, String> valueProvider) {
+        return InMemoryDataProviderHelpers.filteringByCaseInsensitiveString(this, valueProvider,
+                String::startsWith, InMemoryDataProviderHelpers.CURRENT_LOCALE_SUPPLIER);
+    }
+}
diff --git a/server/src/main/java/com/vaadin/data/provider/InMemoryDataProviderHelpers.java b/server/src/main/java/com/vaadin/data/provider/InMemoryDataProviderHelpers.java
new file mode 100644 (file)
index 0000000..5564049
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.data.provider;
+
+import java.util.Comparator;
+import java.util.Locale;
+import java.util.Objects;
+
+import com.vaadin.data.ValueProvider;
+import com.vaadin.server.SerializableBiPredicate;
+import com.vaadin.server.SerializableComparator;
+import com.vaadin.server.SerializablePredicate;
+import com.vaadin.server.SerializableSupplier;
+import com.vaadin.shared.data.sort.SortDirection;
+import com.vaadin.ui.UI;
+
+/**
+ * A class containing a number of static helper methods for implementing
+ * {@link InMemoryDataProvider}s.
+ * <p>
+ * This class is intended primarily for internal use.
+ *
+ * @author Vaadin Ltd
+ * @since 8.1
+ */
+public class InMemoryDataProviderHelpers {
+
+    /**
+     * Supplier that attempts to resolve a locale from the current UI. Returns
+     * the system's default locale as a fallback.
+     */
+    public static final SerializableSupplier<Locale> CURRENT_LOCALE_SUPPLIER = () -> {
+        UI currentUi = UI.getCurrent();
+        if (currentUi != null) {
+            return currentUi.getLocale();
+        } else {
+            return Locale.getDefault();
+        }
+    };
+
+    /**
+     * Wraps a given data provider so that its filter ignores null items
+     * returned by the given value provider.
+     *
+     * @param dataProvider
+     *            the data provider to wrap
+     * @param valueProvider
+     *            the value provider for providing values to filter
+     * @param predicate
+     *            the predicate to combine null filtering with
+     * @return the wrapped data provider
+     */
+    public static <T, V, Q> DataProvider<T, Q> filteringByIgnoreNull(
+            InMemoryDataProvider<T> dataProvider,
+            ValueProvider<T, V> valueProvider,
+            SerializableBiPredicate<V, Q> predicate) {
+        Objects.requireNonNull(predicate, "Predicate cannot be null");
+
+        return dataProvider.filteringBy(valueProvider,
+                (itemValue, queryFilter) -> itemValue != null
+                        && predicate.test(itemValue, queryFilter));
+    }
+
+    /**
+     * Wraps a given data provider so that its filter tests the given predicate
+     * with the lower case string provided by the given value provider.
+     *
+     * @param dataProvider
+     *            the data provider to wrap
+     * @param valueProvider
+     *            the value provider for providing string values to filter
+     * @param predicate
+     *            the predicate to use for comparing the resulting lower case
+     *            strings
+     * @param localeSupplier
+     *            the locale to use when converting strings to lower case
+     * @return the wrapped data provider
+     */
+    public static <T> DataProvider<T, String> filteringByCaseInsensitiveString(
+            InMemoryDataProvider<T> dataProvider,
+            ValueProvider<T, String> valueProvider,
+            SerializableBiPredicate<String, String> predicate,
+            SerializableSupplier<Locale> localeSupplier) {
+        // Only assert since these are only passed from our own code
+        assert predicate != null;
+        assert localeSupplier != null;
+
+        return filteringByIgnoreNull(dataProvider, valueProvider,
+                (itemString, filterString) -> {
+                    Locale locale = localeSupplier.get();
+                    assert locale != null;
+
+                    return predicate.test(itemString.toLowerCase(locale),
+                            filterString.toLowerCase(locale));
+                });
+    }
+
+    /**
+     * Creates a comparator for the return type of the given
+     * {@link ValueProvider}, sorted in the direction specified by the given
+     * {@link SortDirection}.
+     *
+     * @param valueProvider
+     *            the value provider to use
+     * @param sortDirection
+     *            the sort direction to use
+     * @return the created comparator
+     */
+    public static <V extends Comparable<? super V>, T> SerializableComparator<T> propertyComparator(
+            ValueProvider<T, V> valueProvider, SortDirection sortDirection) {
+        Objects.requireNonNull(valueProvider, "Value provider cannot be null");
+        Objects.requireNonNull(sortDirection, "Sort direction cannot be null");
+
+        Comparator<V> comparator = getNaturalSortComparator(sortDirection);
+
+        return (a, b) -> comparator.compare(valueProvider.apply(a),
+                valueProvider.apply(b));
+    }
+
+    /**
+     * Gets the natural order comparator for the type argument, or the natural
+     * order comparator reversed if the given sorting direction is
+     * {@link SortDirection#DESCENDING}.
+     *
+     * @param sortDirection
+     *            the sort direction to use
+     * @return the natural comparator, with ordering defined by the given sort
+     *         direction
+     */
+    public static <V extends Comparable<? super V>> Comparator<V> getNaturalSortComparator(
+            SortDirection sortDirection) {
+        Comparator<V> comparator = Comparator.naturalOrder();
+        if (sortDirection == SortDirection.DESCENDING) {
+            comparator = comparator.reversed();
+        }
+        return comparator;
+    }
+
+    /**
+     * Creates a new predicate from the given predicate and value provider. This
+     * allows using a predicate of the value providers return type with objects
+     * of the value providers type.
+     *
+     * @param valueProvider
+     *            the value provider to use
+     * @param valueFilter
+     *            the original predicate
+     * @return the created predicate
+     */
+    public static <T, V> SerializablePredicate<T> createValueProviderFilter(
+            ValueProvider<T, V> valueProvider,
+            SerializablePredicate<V> valueFilter) {
+        return item -> valueFilter.test(valueProvider.apply(item));
+    }
+
+    /**
+     * Creates a predicate that compares equality of the given required value to
+     * the value the given value provider obtains.
+     *
+     * @param valueProvider
+     *            the value provider to use
+     * @param requiredValue
+     *            the required value
+     * @return the created predicate
+     */
+    public static <T, V> SerializablePredicate<T> createEqualsFilter(
+            ValueProvider<T, V> valueProvider, V requiredValue) {
+        Objects.requireNonNull(valueProvider, "Value provider cannot be null");
+
+        return item -> Objects.equals(valueProvider.apply(item), requiredValue);
+    }
+}
diff --git a/server/src/main/java/com/vaadin/data/provider/InMemoryHierarchicalDataProvider.java b/server/src/main/java/com/vaadin/data/provider/InMemoryHierarchicalDataProvider.java
deleted file mode 100644 (file)
index 8f70dd8..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright 2000-2016 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.vaadin.data.provider;
-
-import java.util.Comparator;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.stream.Stream;
-
-import com.vaadin.data.HierarchyData;
-import com.vaadin.data.ValueProvider;
-import com.vaadin.server.SerializableComparator;
-import com.vaadin.server.SerializableFunction;
-import com.vaadin.server.SerializablePredicate;
-import com.vaadin.shared.data.sort.SortDirection;
-
-/**
- * A {@link DataProvider} for in-memory hierarchical data.
- *
- * @see HierarchyData
- *
- * @author Vaadin Ltd
- * @since 8.1
- *
- * @param <T>
- *            data type
- */
-public class InMemoryHierarchicalDataProvider<T> extends
-        AbstractHierarchicalDataProvider<T, SerializablePredicate<T>> implements
-        ConfigurableFilterDataProvider<T, SerializablePredicate<T>, SerializablePredicate<T>> {
-
-    private final HierarchyData<T> hierarchyData;
-
-    private SerializablePredicate<T> filter = null;
-
-    private SerializableComparator<T> sortOrder = null;
-
-    /**
-     * Constructs a new InMemoryHierarchicalDataProvider.
-     * <p>
-     * All changes made to the given HierarchyData object will also be visible
-     * through this data provider.
-     *
-     * @param hierarchyData
-     *            the backing HierarchyData for this provider
-     */
-    public InMemoryHierarchicalDataProvider(HierarchyData<T> hierarchyData) {
-        this.hierarchyData = hierarchyData;
-    }
-
-    /**
-     * Return the underlying hierarchical data of this provider.
-     *
-     * @return the underlying data of this provider
-     */
-    public HierarchyData<T> getData() {
-        return hierarchyData;
-    }
-
-    @Override
-    public boolean isInMemory() {
-        return true;
-    }
-
-    @Override
-    public boolean hasChildren(T item) {
-        if (!hierarchyData.contains(item)) {
-            throw new IllegalArgumentException("Item " + item
-                    + " could not be found in the backing HierarchyData. "
-                    + "Did you forget to refresh this data provider after item removal?");
-        }
-
-        return !hierarchyData.getChildren(item).isEmpty();
-    }
-
-    @Override
-    public int getChildCount(
-            HierarchicalQuery<T, SerializablePredicate<T>> query) {
-        return (int) fetchChildren(query).count();
-    }
-
-    @Override
-    public Stream<T> fetchChildren(
-            HierarchicalQuery<T, SerializablePredicate<T>> query) {
-        if (!hierarchyData.contains(query.getParent())) {
-            throw new IllegalArgumentException("The queried item "
-                    + query.getParent()
-                    + " could not be found in the backing HierarchyData. "
-                    + "Did you forget to refresh this data provider after item removal?");
-        }
-
-        Stream<T> childStream = getFilteredStream(
-                hierarchyData.getChildren(query.getParent()).stream(),
-                query.getFilter());
-
-        Optional<Comparator<T>> comparing = Stream
-                .of(query.getInMemorySorting(), sortOrder)
-                .filter(c -> c != null)
-                .reduce((c1, c2) -> c1.thenComparing(c2));
-
-        if (comparing.isPresent()) {
-            childStream = childStream.sorted(comparing.get());
-        }
-
-        return childStream.skip(query.getOffset()).limit(query.getLimit());
-    }
-
-    @Override
-    public void setFilter(SerializablePredicate<T> filter) {
-        this.filter = filter;
-        refreshAll();
-    }
-
-    /**
-     * Adds a filter to be applied to all queries. The filter will be used in
-     * addition to any filter that has been set or added previously.
-     *
-     * @see #addFilter(ValueProvider, SerializablePredicate)
-     * @see #addFilterByValue(ValueProvider, Object)
-     * @see #setFilter(SerializablePredicate)
-     *
-     * @param filter
-     *            the filter to add, not <code>null</code>
-     */
-    public void addFilter(SerializablePredicate<T> filter) {
-        Objects.requireNonNull(filter, "Filter cannot be null");
-
-        if (this.filter == null) {
-            setFilter(filter);
-        } else {
-            SerializablePredicate<T> oldFilter = this.filter;
-            setFilter(item -> oldFilter.test(item) && filter.test(item));
-        }
-    }
-
-    /**
-     * Sets the comparator to use as the default sorting for this data provider.
-     * This overrides the sorting set by any other method that manipulates the
-     * default sorting of this data provider.
-     * <p>
-     * The default sorting is used if the query defines no sorting. The default
-     * sorting is also used to determine the ordering of items that are
-     * considered equal by the sorting defined in the query.
-     *
-     * @see #setSortOrder(ValueProvider, SortDirection)
-     * @see #addSortComparator(SerializableComparator)
-     *
-     * @param comparator
-     *            a comparator to use, or <code>null</code> to clear any
-     *            previously set sort order
-     */
-    public void setSortComparator(SerializableComparator<T> comparator) {
-        sortOrder = comparator;
-        refreshAll();
-    }
-
-    /**
-     * Adds a comparator to the default sorting for this data provider. If no
-     * default sorting has been defined, then the provided comparator will be
-     * used as the default sorting. If a default sorting has been defined, then
-     * the provided comparator will be used to determine the ordering of items
-     * that are considered equal by the previously defined default sorting.
-     * <p>
-     * The default sorting is used if the query defines no sorting. The default
-     * sorting is also used to determine the ordering of items that are
-     * considered equal by the sorting defined in the query.
-     *
-     * @see #setSortComparator(SerializableComparator)
-     * @see #addSortOrder(ValueProvider, SortDirection)
-     *
-     * @param comparator
-     *            a comparator to add, not <code>null</code>
-     */
-    public void addSortComparator(SerializableComparator<T> comparator) {
-        Objects.requireNonNull(comparator, "Sort order to add cannot be null");
-        SerializableComparator<T> originalComparator = sortOrder;
-        if (originalComparator == null) {
-            setSortComparator(comparator);
-        } else {
-            setSortComparator((a, b) -> {
-                int result = originalComparator.compare(a, b);
-                if (result == 0) {
-                    result = comparator.compare(a, b);
-                }
-                return result;
-            });
-        }
-    }
-
-    @Override
-    public <C> DataProvider<T, C> withConvertedFilter(
-            SerializableFunction<C, SerializablePredicate<T>> filterConverter) {
-        Objects.requireNonNull(filterConverter,
-                "Filter converter can't be null");
-        return new DataProviderWrapper<T, C, SerializablePredicate<T>>(this) {
-
-            @Override
-            protected SerializablePredicate<T> getFilter(Query<T, C> query) {
-                return query.getFilter().map(filterConverter).orElse(null);
-            }
-
-            @Override
-            public int size(Query<T, C> t) {
-                if (t instanceof HierarchicalQuery<?, ?>) {
-                    return dataProvider.size(new HierarchicalQuery<>(
-                            t.getOffset(), t.getLimit(), t.getSortOrders(),
-                            t.getInMemorySorting(), getFilter(t),
-                            ((HierarchicalQuery<T, C>) t).getParent()));
-                }
-                throw new IllegalArgumentException(
-                        "Hierarchical data provider doesn't support non-hierarchical queries");
-            }
-
-            @Override
-            public Stream<T> fetch(Query<T, C> t) {
-                if (t instanceof HierarchicalQuery<?, ?>) {
-                    return dataProvider.fetch(new HierarchicalQuery<>(
-                            t.getOffset(), t.getLimit(), t.getSortOrders(),
-                            t.getInMemorySorting(), getFilter(t),
-                            ((HierarchicalQuery<T, C>) t).getParent()));
-                }
-                throw new IllegalArgumentException(
-                        "Hierarchical data provider doesn't support non-hierarchical queries");
-            }
-        };
-    }
-
-    private Stream<T> getFilteredStream(Stream<T> stream,
-            Optional<SerializablePredicate<T>> queryFilter) {
-        if (filter != null) {
-            stream = stream.filter(filter);
-        }
-        return queryFilter.map(stream::filter).orElse(stream);
-    }
-}
index fba2f94d9d1859ab6a3c9e7cd45742731673cbd5..eef0b0388e8f1281bcd527bbf41eb81c09618176 100644 (file)
@@ -17,18 +17,12 @@ package com.vaadin.data.provider;
 
 import java.util.Collection;
 import java.util.Comparator;
-import java.util.Locale;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.stream.Stream;
 
-import com.vaadin.data.ValueProvider;
-import com.vaadin.server.SerializableBiPredicate;
 import com.vaadin.server.SerializableComparator;
 import com.vaadin.server.SerializablePredicate;
-import com.vaadin.server.SerializableSupplier;
-import com.vaadin.shared.data.sort.SortDirection;
-import com.vaadin.ui.UI;
 
 /**
  * {@link DataProvider} wrapper for {@link Collection}s.
@@ -38,17 +32,8 @@ import com.vaadin.ui.UI;
  * @since 8.0
  */
 public class ListDataProvider<T>
-        extends AbstractDataProvider<T, SerializablePredicate<T>> implements
-        ConfigurableFilterDataProvider<T, SerializablePredicate<T>, SerializablePredicate<T>> {
-
-    private static final SerializableSupplier<Locale> CURRENT_LOCALE_SUPPLIER = () -> {
-        UI currentUi = UI.getCurrent();
-        if (currentUi != null) {
-            return currentUi.getLocale();
-        } else {
-            return Locale.getDefault();
-        }
-    };
+        extends AbstractDataProvider<T, SerializablePredicate<T>>
+        implements InMemoryDataProvider<T> {
 
     private SerializableComparator<T> sortOrder = null;
 
@@ -97,11 +82,6 @@ public class ListDataProvider<T>
         return stream.skip(query.getOffset()).limit(query.getLimit());
     }
 
-    @Override
-    public boolean isInMemory() {
-        return true;
-    }
-
     @Override
     public int size(Query<T, SerializablePredicate<T>> query) {
         return (int) getFilteredStream(query).count();
@@ -122,454 +102,25 @@ public class ListDataProvider<T>
         return stream;
     }
 
-    /**
-     * Sets the comparator to use as the default sorting for this data provider.
-     * This overrides the sorting set by any other method that manipulates the
-     * default sorting of this data provider.
-     * <p>
-     * The default sorting is used if the query defines no sorting. The default
-     * sorting is also used to determine the ordering of items that are
-     * considered equal by the sorting defined in the query.
-     *
-     * @see #setSortOrder(ValueProvider, SortDirection)
-     * @see #addSortComparator(SerializableComparator)
-     *
-     * @param comparator
-     *            a comparator to use, or <code>null</code> to clear any
-     *            previously set sort order
-     */
+    @Override
+    public SerializableComparator<T> getSortComparator() {
+        return sortOrder;
+    }
+
+    @Override
     public void setSortComparator(SerializableComparator<T> comparator) {
         this.sortOrder = comparator;
         refreshAll();
     }
 
-    /**
-     * Sets the property and direction to use as the default sorting for this
-     * data provider. This overrides the sorting set by any other method that
-     * manipulates the default sorting of this data provider.
-     * <p>
-     * The default sorting is used if the query defines no sorting. The default
-     * sorting is also used to determine the ordering of items that are
-     * considered equal by the sorting defined in the query.
-     *
-     * @see #setSortComparator(SerializableComparator)
-     * @see #addSortOrder(ValueProvider, SortDirection)
-     *
-     * @param valueProvider
-     *            the value provider that defines the property do sort by, not
-     *            <code>null</code>
-     * @param sortDirection
-     *            the sort direction to use, not <code>null</code>
-     */
-    public <V extends Comparable<? super V>> void setSortOrder(
-            ValueProvider<T, V> valueProvider, SortDirection sortDirection) {
-        setSortComparator(propertyComparator(valueProvider, sortDirection));
-    }
-
-    /**
-     * Adds a comparator to the default sorting for this data provider. If no
-     * default sorting has been defined, then the provided comparator will be
-     * used as the default sorting. If a default sorting has been defined, then
-     * the provided comparator will be used to determine the ordering of items
-     * that are considered equal by the previously defined default sorting.
-     * <p>
-     * The default sorting is used if the query defines no sorting. The default
-     * sorting is also used to determine the ordering of items that are
-     * considered equal by the sorting defined in the query.
-     *
-     * @see #setSortComparator(SerializableComparator)
-     * @see #addSortOrder(ValueProvider, SortDirection)
-     *
-     * @param comparator
-     *            a comparator to add, not <code>null</code>
-     */
-    public void addSortComparator(SerializableComparator<T> comparator) {
-        Objects.requireNonNull(comparator, "Sort order to add cannot be null");
-
-        SerializableComparator<T> originalComparator = this.sortOrder;
-        if (originalComparator == null) {
-            setSortComparator(comparator);
-        } else {
-            setSortComparator((a, b) -> {
-                int result = originalComparator.compare(a, b);
-                if (result == 0) {
-                    result = comparator.compare(a, b);
-                }
-                return result;
-            });
-        }
-    }
-
-    /**
-     * Adds a property and direction to the default sorting for this data
-     * provider. If no default sorting has been defined, then the provided sort
-     * order will be used as the default sorting. If a default sorting has been
-     * defined, then the provided sort order will be used to determine the
-     * ordering of items that are considered equal by the previously defined
-     * default sorting.
-     * <p>
-     * The default sorting is used if the query defines no sorting. The default
-     * sorting is also used to determine the ordering of items that are
-     * considered equal by the sorting defined in the query.
-     *
-     * @see #setSortOrder(ValueProvider, SortDirection)
-     * @see #addSortComparator(SerializableComparator)
-     *
-     * @param valueProvider
-     *            the value provider that defines the property do sort by, not
-     *            <code>null</code>
-     * @param sortDirection
-     *            the sort direction to use, not <code>null</code>
-     */
-    public <V extends Comparable<? super V>> void addSortOrder(
-            ValueProvider<T, V> valueProvider, SortDirection sortDirection) {
-        addSortComparator(propertyComparator(valueProvider, sortDirection));
-    }
-
-    private static <V extends Comparable<? super V>, T> SerializableComparator<T> propertyComparator(
-            ValueProvider<T, V> valueProvider, SortDirection sortDirection) {
-        Objects.requireNonNull(valueProvider, "Value provider cannot be null");
-        Objects.requireNonNull(sortDirection, "Sort direction cannot be null");
-
-        Comparator<V> comparator = getNaturalSortComparator(sortDirection);
-
-        return (a, b) -> comparator.compare(valueProvider.apply(a),
-                valueProvider.apply(b));
-    }
-
-    private static <V extends Comparable<? super V>> Comparator<V> getNaturalSortComparator(
-            SortDirection sortDirection) {
-        Comparator<V> comparator = Comparator.naturalOrder();
-        if (sortDirection == SortDirection.DESCENDING) {
-            comparator = comparator.reversed();
-        }
-        return comparator;
+    @Override
+    public SerializablePredicate<T> getFilter() {
+        return filter;
     }
 
-    /**
-     * Sets a filter to be applied to all queries. The filter replaces any
-     * filter that has been set or added previously.
-     *
-     * @see #setFilter(ValueProvider, SerializablePredicate)
-     * @see #setFilterByValue(ValueProvider, Object)
-     * @see #addFilter(SerializablePredicate)
-     *
-     * @param filter
-     *            the filter to set, or <code>null</code> to remove any set
-     *            filters
-     */
     @Override
     public void setFilter(SerializablePredicate<T> filter) {
         this.filter = filter;
         refreshAll();
     }
-
-    /**
-     * Adds a filter to be applied to all queries. The filter will be used in
-     * addition to any filter that has been set or added previously.
-     *
-     * @see #addFilter(ValueProvider, SerializablePredicate)
-     * @see #addFilterByValue(ValueProvider, Object)
-     * @see #setFilter(SerializablePredicate)
-     *
-     * @param filter
-     *            the filter to add, not <code>null</code>
-     */
-    public void addFilter(SerializablePredicate<T> filter) {
-        Objects.requireNonNull(filter, "Filter cannot be null");
-
-        if (this.filter == null) {
-            setFilter(filter);
-        } else {
-            SerializablePredicate<T> oldFilter = this.filter;
-            setFilter(item -> oldFilter.test(item) && filter.test(item));
-        }
-    }
-
-    /**
-     * Removes any filter that has been set or added previously.
-     *
-     * @see #setFilter(SerializablePredicate)
-     */
-    public void clearFilters() {
-        setFilter(null);
-    }
-
-    /**
-     * Sets a filter for an item property. The filter replaces any filter that
-     * has been set or added previously.
-     *
-     * @see #setFilter(SerializablePredicate)
-     * @see #setFilterByValue(ValueProvider, Object)
-     * @see #addFilter(ValueProvider, SerializablePredicate)
-     *
-     * @param valueProvider
-     *            value provider that gets the property value, not
-     *            <code>null</code>
-     * @param valueFilter
-     *            filter for testing the property value, not <code>null</code>
-     */
-    public <V> void setFilter(ValueProvider<T, V> valueProvider,
-            SerializablePredicate<V> valueFilter) {
-        setFilter(createValueProviderFilter(valueProvider, valueFilter));
-    }
-
-    /**
-     * Adds a filter for an item property. The filter will be used in addition
-     * to any filter that has been set or added previously.
-     *
-     * @see #addFilter(SerializablePredicate)
-     * @see #addFilterByValue(ValueProvider, Object)
-     * @see #setFilter(ValueProvider, SerializablePredicate)
-     *
-     * @param valueProvider
-     *            value provider that gets the property value, not
-     *            <code>null</code>
-     * @param valueFilter
-     *            filter for testing the property value, not <code>null</code>
-     */
-    public <V> void addFilter(ValueProvider<T, V> valueProvider,
-            SerializablePredicate<V> valueFilter) {
-        Objects.requireNonNull(valueProvider, "Value provider cannot be null");
-        Objects.requireNonNull(valueFilter, "Value filter cannot be null");
-
-        addFilter(createValueProviderFilter(valueProvider, valueFilter));
-    }
-
-    private static <T, V> SerializablePredicate<T> createValueProviderFilter(
-            ValueProvider<T, V> valueProvider,
-            SerializablePredicate<V> valueFilter) {
-        return item -> valueFilter.test(valueProvider.apply(item));
-    }
-
-    /**
-     * Sets a filter that requires an item property to have a specific value.
-     * The property value and the provided value are compared using
-     * {@link Object#equals(Object)}. The filter replaces any filter that has
-     * been set or added previously.
-     *
-     * @see #setFilter(SerializablePredicate)
-     * @see #setFilter(ValueProvider, SerializablePredicate)
-     * @see #addFilterByValue(ValueProvider, Object)
-     *
-     * @param valueProvider
-     *            value provider that gets the property value, not
-     *            <code>null</code>
-     * @param requiredValue
-     *            the value that the property must have for the filter to pass
-     */
-    public <V> void setFilterByValue(ValueProvider<T, V> valueProvider,
-            V requiredValue) {
-        setFilter(createEqualsFilter(valueProvider, requiredValue));
-    }
-
-    /**
-     * Adds a filter that requires an item property to have a specific value.
-     * The property value and the provided value are compared using
-     * {@link Object#equals(Object)}.The filter will be used in addition to any
-     * filter that has been set or added previously.
-     *
-     * @see #setFilterByValue(ValueProvider, Object)
-     * @see #addFilter(SerializablePredicate)
-     * @see #addFilter(ValueProvider, SerializablePredicate)
-     *
-     * @param valueProvider
-     *            value provider that gets the property value, not
-     *            <code>null</code>
-     * @param requiredValue
-     *            the value that the property must have for the filter to pass
-     */
-    public <V> void addFilterByValue(ValueProvider<T, V> valueProvider,
-            V requiredValue) {
-        addFilter(createEqualsFilter(valueProvider, requiredValue));
-    }
-
-    private static <T, V> SerializablePredicate<T> createEqualsFilter(
-            ValueProvider<T, V> valueProvider, V requiredValue) {
-        Objects.requireNonNull(valueProvider, "Value provider cannot be null");
-
-        return item -> Objects.equals(valueProvider.apply(item), requiredValue);
-    }
-
-    /**
-     * Wraps this data provider to create a new data provider that is filtered
-     * by comparing an item to the filter value provided in the query.
-     * <p>
-     * The predicate receives the item as the first parameter and the query
-     * filter value as the second parameter, and should return <code>true</code>
-     * if the corresponding item should be included. The query filter value is
-     * never <code>null</code> – all items are included without running the
-     * predicate if the query doesn't define any filter.
-     *
-     * @param predicate
-     *            a predicate to use for comparing the item to the query filter,
-     *            not <code>null</code>
-     *
-     * @return a data provider that filters accordingly, not <code>null</code>
-     */
-    public <Q> DataProvider<T, Q> filteringBy(
-            SerializableBiPredicate<T, Q> predicate) {
-        Objects.requireNonNull(predicate, "Predicate cannot be null");
-
-        return withConvertedFilter(
-                filterValue -> item -> predicate.test(item, filterValue));
-    }
-
-    /**
-     * Wraps this data provider to create a new data provider that is filtered
-     * by comparing an item property value to the filter value provided in the
-     * query.
-     * <p>
-     * The predicate receives the property value as the first parameter and the
-     * query filter value as the second parameter, and should return
-     * <code>true</code> if the corresponding item should be included. The query
-     * filter value is never <code>null</code> – all items are included without
-     * running either callback if the query doesn't define any filter.
-     *
-     * @param valueProvider
-     *            a value provider that gets the property value, not
-     *            <code>null</code>
-     * @param predicate
-     *            a predicate to use for comparing the property value to the
-     *            query filter, not <code>null</code>
-     *
-     * @return a data provider that filters accordingly, not <code>null</code>
-     */
-    public <V, Q> DataProvider<T, Q> filteringBy(
-            ValueProvider<T, V> valueProvider,
-            SerializableBiPredicate<V, Q> predicate) {
-        Objects.requireNonNull(valueProvider, "Value provider cannot be null");
-        Objects.requireNonNull(predicate, "Predicate cannot be null");
-
-        return filteringBy((item, filterValue) -> predicate
-                .test(valueProvider.apply(item), filterValue));
-    }
-
-    /**
-     * Wraps this data provider to create a new data provider that is filtered
-     * by testing whether the value of a property is equals to the filter value
-     * provided in the query. Equality is tested using
-     * {@link Objects#equals(Object, Object)}.
-     *
-     * @param valueProvider
-     *            a value provider that gets the property value, not
-     *            <code>null</code>
-     *
-     * @return a data provider that filters accordingly, not <code>null</code>
-     */
-    public <V> DataProvider<T, V> filteringByEquals(
-            ValueProvider<T, V> valueProvider) {
-        return filteringBy(valueProvider, Objects::equals);
-    }
-
-    private <V, Q> DataProvider<T, Q> filteringByIgnoreNull(
-            ValueProvider<T, V> valueProvider,
-            SerializableBiPredicate<V, Q> predicate) {
-        Objects.requireNonNull(predicate, "Predicate cannot be null");
-
-        return filteringBy(valueProvider,
-                (itemValue, queryFilter) -> itemValue != null
-                        && predicate.test(itemValue, queryFilter));
-    }
-
-    /**
-     * Wraps this data provider to create a new data provider that is filtered
-     * by a string by checking whether the lower case representation of the
-     * filter value provided in the query is a substring of the lower case
-     * representation of an item property value. The filter never passes if the
-     * item property value is <code>null</code>.
-     *
-     * @param valueProvider
-     *            a value provider that gets the string property value, not
-     *            <code>null</code>
-     * @param locale
-     *            the locale to use for converting the strings to lower case,
-     *            not <code>null</code>
-     * @return a data provider that filters accordingly, not <code>null</code>
-     */
-    public DataProvider<T, String> filteringBySubstring(
-            ValueProvider<T, String> valueProvider, Locale locale) {
-        Objects.requireNonNull(locale, "Locale cannot be null");
-        return filteringByCaseInsensitiveString(valueProvider, String::contains,
-                () -> locale);
-    }
-
-    /**
-     * Wraps this data provider to create a new data provider that is filtered
-     * by a string by checking whether the lower case representation of the
-     * filter value provided in the query is a substring of the lower case
-     * representation of an item property value. Conversion to lower case is
-     * done using the locale of the {@link UI#getCurrent() current UI} if
-     * available, or otherwise {@link Locale#getDefault() the default locale}.
-     * The filter never passes if the item property value is <code>null</code>.
-     *
-     * @param valueProvider
-     *            a value provider that gets the string property value, not
-     *            <code>null</code>
-     * @return a data provider that filters accordingly, not <code>null</code>
-     */
-    public DataProvider<T, String> filteringBySubstring(
-            ValueProvider<T, String> valueProvider) {
-        return filteringByCaseInsensitiveString(valueProvider, String::contains,
-                CURRENT_LOCALE_SUPPLIER);
-    }
-
-    /**
-     * Wraps this data provider to create a new data provider that is filtered
-     * by a string by checking whether the lower case representation of an item
-     * property value starts with the lower case representation of the filter
-     * value provided in the query. The filter never passes if the item property
-     * value is <code>null</code>.
-     *
-     * @param valueProvider
-     *            a value provider that gets the string property value, not
-     *            <code>null</code>
-     * @param locale
-     *            the locale to use for converting the strings to lower case,
-     *            not <code>null</code>
-     * @return a data provider that filters accordingly, not <code>null</code>
-     */
-    public DataProvider<T, String> filteringByPrefix(
-            ValueProvider<T, String> valueProvider, Locale locale) {
-        return filteringByCaseInsensitiveString(valueProvider,
-                String::startsWith, () -> locale);
-    }
-
-    /**
-     * Wraps this data provider to create a new data provider that is filtered
-     * by a string by checking whether the lower case representation of an item
-     * property value starts with the lower case representation of the filter
-     * value provided in the query. Conversion to lower case is done using the
-     * locale of the {@link UI#getCurrent() current UI} if available, or
-     * otherwise {@link Locale#getDefault() the default locale}. The filter
-     * never passes if the item property value is <code>null</code>.
-     *
-     * @param valueProvider
-     *            a value provider that gets the string property value, not
-     *            <code>null</code>
-     * @return a data provider that filters accordingly, not <code>null</code>
-     */
-    public DataProvider<T, String> filteringByPrefix(
-            ValueProvider<T, String> valueProvider) {
-        return filteringByCaseInsensitiveString(valueProvider,
-                String::startsWith, CURRENT_LOCALE_SUPPLIER);
-    }
-
-    private DataProvider<T, String> filteringByCaseInsensitiveString(
-            ValueProvider<T, String> valueProvider,
-            SerializableBiPredicate<String, String> predicate,
-            SerializableSupplier<Locale> localeSupplier) {
-        // Only assert since these are only passed from our own code
-        assert predicate != null;
-        assert localeSupplier != null;
-
-        return filteringByIgnoreNull(valueProvider,
-                (itemString, filterString) -> {
-                    Locale locale = localeSupplier.get();
-                    assert locale != null;
-
-                    return predicate.test(itemString.toLowerCase(locale),
-                            filterString.toLowerCase(locale));
-                });
-    }
 }
diff --git a/server/src/main/java/com/vaadin/data/provider/TreeDataProvider.java b/server/src/main/java/com/vaadin/data/provider/TreeDataProvider.java
new file mode 100644 (file)
index 0000000..b30a286
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.data.provider;
+
+import java.util.Comparator;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import com.vaadin.data.TreeData;
+import com.vaadin.server.SerializableComparator;
+import com.vaadin.server.SerializableFunction;
+import com.vaadin.server.SerializablePredicate;
+
+/**
+ * {@link HierarchicalDataProvider} wrapper for {@link TreeData}.
+ *
+ * @author Vaadin Ltd
+ * @since 8.1
+ *
+ * @param <T>
+ *            data type
+ */
+public class TreeDataProvider<T>
+        extends AbstractHierarchicalDataProvider<T, SerializablePredicate<T>>
+        implements InMemoryDataProvider<T> {
+
+    private final TreeData<T> treeData;
+
+    private SerializablePredicate<T> filter = null;
+
+    private SerializableComparator<T> sortOrder = null;
+
+    /**
+     * Constructs a new TreeDataProvider.
+     * <p>
+     * All changes made to the given {@link TreeData} object will also be
+     * visible through this data provider.
+     *
+     * @param treeData
+     *            the backing {@link TreeData} for this provider
+     */
+    public TreeDataProvider(TreeData<T> treeData) {
+        this.treeData = treeData;
+    }
+
+    /**
+     * Return the underlying hierarchical data of this provider.
+     *
+     * @return the underlying data of this provider
+     */
+    public TreeData<T> getTreeData() {
+        return treeData;
+    }
+
+    @Override
+    public boolean hasChildren(T item) {
+        if (!treeData.contains(item)) {
+            throw new IllegalArgumentException("Item " + item
+                    + " could not be found in the backing TreeData. "
+                    + "Did you forget to refresh this data provider after item removal?");
+        }
+
+        return !treeData.getChildren(item).isEmpty();
+    }
+
+    @Override
+    public int getChildCount(
+            HierarchicalQuery<T, SerializablePredicate<T>> query) {
+        return (int) fetchChildren(query).count();
+    }
+
+    @Override
+    public Stream<T> fetchChildren(
+            HierarchicalQuery<T, SerializablePredicate<T>> query) {
+        if (!treeData.contains(query.getParent())) {
+            throw new IllegalArgumentException("The queried item "
+                    + query.getParent()
+                    + " could not be found in the backing TreeData. "
+                    + "Did you forget to refresh this data provider after item removal?");
+        }
+
+        Stream<T> childStream = getFilteredStream(
+                treeData.getChildren(query.getParent()).stream(),
+                query.getFilter());
+
+        Optional<Comparator<T>> comparing = Stream
+                .of(query.getInMemorySorting(), sortOrder)
+                .filter(c -> c != null)
+                .reduce((c1, c2) -> c1.thenComparing(c2));
+
+        if (comparing.isPresent()) {
+            childStream = childStream.sorted(comparing.get());
+        }
+
+        return childStream.skip(query.getOffset()).limit(query.getLimit());
+    }
+
+    @Override
+    public SerializablePredicate<T> getFilter() {
+        return filter;
+    }
+
+    @Override
+    public void setFilter(SerializablePredicate<T> filter) {
+        this.filter = filter;
+        refreshAll();
+    }
+
+    @Override
+    public SerializableComparator<T> getSortComparator() {
+        return sortOrder;
+    }
+
+    @Override
+    public void setSortComparator(SerializableComparator<T> comparator) {
+        sortOrder = comparator;
+        refreshAll();
+    }
+
+    @Override
+    public <C> DataProvider<T, C> withConvertedFilter(
+            SerializableFunction<C, SerializablePredicate<T>> filterConverter) {
+        Objects.requireNonNull(filterConverter,
+                "Filter converter can't be null");
+        return new DataProviderWrapper<T, C, SerializablePredicate<T>>(this) {
+
+            @Override
+            protected SerializablePredicate<T> getFilter(Query<T, C> query) {
+                return query.getFilter().map(filterConverter).orElse(null);
+            }
+
+            @Override
+            public int size(Query<T, C> t) {
+                if (t instanceof HierarchicalQuery<?, ?>) {
+                    return dataProvider.size(new HierarchicalQuery<>(
+                            t.getOffset(), t.getLimit(), t.getSortOrders(),
+                            t.getInMemorySorting(), getFilter(t),
+                            ((HierarchicalQuery<T, C>) t).getParent()));
+                }
+                throw new IllegalArgumentException(
+                        "Hierarchical data provider doesn't support non-hierarchical queries");
+            }
+
+            @Override
+            public Stream<T> fetch(Query<T, C> t) {
+                if (t instanceof HierarchicalQuery<?, ?>) {
+                    return dataProvider.fetch(new HierarchicalQuery<>(
+                            t.getOffset(), t.getLimit(), t.getSortOrders(),
+                            t.getInMemorySorting(), getFilter(t),
+                            ((HierarchicalQuery<T, C>) t).getParent()));
+                }
+                throw new IllegalArgumentException(
+                        "Hierarchical data provider doesn't support non-hierarchical queries");
+            }
+        };
+    }
+
+    private Stream<T> getFilteredStream(Stream<T> stream,
+            Optional<SerializablePredicate<T>> queryFilter) {
+        if (filter != null) {
+            stream = stream.filter(filter);
+        }
+        return queryFilter.map(stream::filter).orElse(stream);
+    }
+}
index 97e1b94cecd96ca87744fb035c6a95468ba373ec..9a765238c1264ebe3e3a10ddec09e4267b9e0dcb 100644 (file)
@@ -24,7 +24,7 @@ import java.util.Objects;
 import java.util.Set;
 
 import com.vaadin.data.Binder;
-import com.vaadin.data.HasDataProvider;
+import com.vaadin.data.HasHierarchicalDataProvider;
 import com.vaadin.data.SelectionModel;
 import com.vaadin.data.provider.DataGenerator;
 import com.vaadin.data.provider.DataProvider;
@@ -57,7 +57,8 @@ import elemental.json.JsonObject;
  * @param <T>
  *            the data type
  */
-public class Tree<T> extends Composite implements HasDataProvider<T> {
+public class Tree<T> extends Composite
+        implements HasHierarchicalDataProvider<T> {
 
     @Deprecated
     private static final Method ITEM_CLICK_METHOD = ReflectTools
@@ -422,11 +423,6 @@ public class Tree<T> extends Composite implements HasDataProvider<T> {
         return treeGrid.getSelectionModel();
     }
 
-    @Override
-    public void setItems(Collection<T> items) {
-        treeGrid.setItems(items);
-    }
-
     /**
      * Sets the item caption generator that is used to produce the strings shown
      * as the text for each item. By default, {@link String#valueOf(Object)} is
index 720bffaf3eec37f0534f2c734527c144c8d2bfd4..1b051d1da6a5787fcc13078cfecf2cdef56551da 100644 (file)
@@ -21,19 +21,19 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
-import java.util.stream.Stream;
 
 import org.jsoup.nodes.Attributes;
 import org.jsoup.nodes.Element;
 import org.jsoup.select.Elements;
 
-import com.vaadin.data.HierarchyData;
+import com.vaadin.data.HasHierarchicalDataProvider;
+import com.vaadin.data.TreeData;
 import com.vaadin.data.ValueProvider;
 import com.vaadin.data.provider.DataProvider;
 import com.vaadin.data.provider.HierarchicalDataCommunicator;
 import com.vaadin.data.provider.HierarchicalDataProvider;
 import com.vaadin.data.provider.HierarchicalQuery;
-import com.vaadin.data.provider.InMemoryHierarchicalDataProvider;
+import com.vaadin.data.provider.TreeDataProvider;
 import com.vaadin.event.CollapseEvent;
 import com.vaadin.event.CollapseEvent.CollapseListener;
 import com.vaadin.event.ExpandEvent;
@@ -60,7 +60,8 @@ import com.vaadin.ui.renderers.Renderer;
  * @param <T>
  *            the grid bean type
  */
-public class TreeGrid<T> extends Grid<T> {
+public class TreeGrid<T> extends Grid<T>
+        implements HasHierarchicalDataProvider<T> {
 
     public TreeGrid() {
         super(new HierarchicalDataCommunicator<>());
@@ -125,117 +126,6 @@ public class TreeGrid<T> extends Grid<T> {
                 CollapseListener.COLLAPSE_METHOD);
     }
 
-    /**
-     * Sets the data items of this component provided as a collection.
-     * <p>
-     * The provided items are wrapped into a
-     * {@link InMemoryHierarchicalDataProvider} backed by a flat
-     * {@link HierarchyData} structure. The data provider instance is used as a
-     * parameter for the {@link #setDataProvider(DataProvider)} method. It means
-     * that the items collection can be accessed later on via
-     * {@link InMemoryHierarchicalDataProvider#getData()}:
-     *
-     * <pre>
-     * <code>
-     * TreeGrid<String> treeGrid = new TreeGrid<>();
-     * treeGrid.setItems(Arrays.asList("a","b"));
-     * ...
-     *
-     * HierarchyData<String> data = ((InMemoryHierarchicalDataProvider<String>)treeGrid.getDataProvider()).getData();
-     * </code>
-     * </pre>
-     * <p>
-     * The returned HierarchyData instance may be used as-is to add, remove or
-     * modify items in the hierarchy. These modifications to the object are not
-     * automatically reflected back to the TreeGrid. Items modified should be
-     * refreshed with {@link HierarchicalDataProvider#refreshItem(Object)} and
-     * when adding or removing items
-     * {@link HierarchicalDataProvider#refreshAll()} should be called.
-     *
-     * @param items
-     *            the data items to display, not null
-     */
-    @Override
-    public void setItems(Collection<T> items) {
-        Objects.requireNonNull(items, "Given collection may not be null");
-        setDataProvider(new InMemoryHierarchicalDataProvider<>(
-                new HierarchyData<T>().addItems(null, items)));
-    }
-
-    /**
-     * Sets the data items of this component provided as a stream.
-     * <p>
-     * The provided items are wrapped into a
-     * {@link InMemoryHierarchicalDataProvider} backed by a flat
-     * {@link HierarchyData} structure. The data provider instance is used as a
-     * parameter for the {@link #setDataProvider(DataProvider)} method. It means
-     * that the items collection can be accessed later on via
-     * {@link InMemoryHierarchicalDataProvider#getData()}:
-     *
-     * <pre>
-     * <code>
-     * TreeGrid<String> treeGrid = new TreeGrid<>();
-     * treeGrid.setItems(Stream.of("a","b"));
-     * ...
-     *
-     * HierarchyData<String> data = ((InMemoryHierarchicalDataProvider<String>)treeGrid.getDataProvider()).getData();
-     * </code>
-     * </pre>
-     * <p>
-     * The returned HierarchyData instance may be used as-is to add, remove or
-     * modify items in the hierarchy. These modifications to the object are not
-     * automatically reflected back to the TreeGrid. Items modified should be
-     * refreshed with {@link HierarchicalDataProvider#refreshItem(Object)} and
-     * when adding or removing items
-     * {@link HierarchicalDataProvider#refreshAll()} should be called.
-     *
-     * @param items
-     *            the data items to display, not null
-     */
-    @Override
-    public void setItems(Stream<T> items) {
-        Objects.requireNonNull(items, "Given stream may not be null");
-        setDataProvider(new InMemoryHierarchicalDataProvider<>(
-                new HierarchyData<T>().addItems(null, items)));
-    }
-
-    /**
-     * Sets the data items of this listing.
-     * <p>
-     * The provided items are wrapped into a
-     * {@link InMemoryHierarchicalDataProvider} backed by a flat
-     * {@link HierarchyData} structure. The data provider instance is used as a
-     * parameter for the {@link #setDataProvider(DataProvider)} method. It means
-     * that the items collection can be accessed later on via
-     * {@link InMemoryHierarchicalDataProvider#getData()}:
-     *
-     * <pre>
-     * <code>
-     * TreeGrid<String> treeGrid = new TreeGrid<>();
-     * treeGrid.setItems("a","b");
-     * ...
-     *
-     * HierarchyData<String> data = ((InMemoryHierarchicalDataProvider<String>)treeGrid.getDataProvider()).getData();
-     * </code>
-     * </pre>
-     * <p>
-     * The returned HierarchyData instance may be used as-is to add, remove or
-     * modify items in the hierarchy. These modifications to the object are not
-     * automatically reflected back to the TreeGrid. Items modified should be
-     * refreshed with {@link HierarchicalDataProvider#refreshItem(Object)} and
-     * when adding or removing items
-     * {@link HierarchicalDataProvider#refreshAll()} should be called.
-     *
-     * @param items
-     *            the data items to display, not null
-     */
-    @Override
-    public void setItems(@SuppressWarnings("unchecked") T... items) {
-        Objects.requireNonNull(items, "Given items may not be null");
-        setDataProvider(new InMemoryHierarchicalDataProvider<>(
-                new HierarchyData<T>().addItems(null, items)));
-    }
-
     @Override
     public void setDataProvider(DataProvider<T, ?> dataProvider) {
         if (!(dataProvider instanceof HierarchicalDataProvider)) {
@@ -395,7 +285,7 @@ public class TreeGrid<T> extends Grid<T> {
             List<DeclarativeValueProvider<T>> providers) {
         getSelectionModel().deselectAll();
         List<T> selectedItems = new ArrayList<>();
-        HierarchyData<T> data = new HierarchyData<T>();
+        TreeData<T> data = new TreeData<T>();
 
         for (Element row : body.children()) {
             T item = deserializeDeclarativeRepresentation(row.attr("item"));
@@ -416,7 +306,7 @@ public class TreeGrid<T> extends Grid<T> {
             }
         }
 
-        setDataProvider(new InMemoryHierarchicalDataProvider<>(data));
+        setDataProvider(new TreeDataProvider<>(data));
         selectedItems.forEach(getSelectionModel()::select);
     }
 
diff --git a/server/src/test/java/com/vaadin/data/provider/InMemoryHierarchicalDataProviderTest.java b/server/src/test/java/com/vaadin/data/provider/InMemoryHierarchicalDataProviderTest.java
deleted file mode 100644 (file)
index 99b7a04..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-package com.vaadin.data.provider;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-import com.vaadin.data.HierarchyData;
-import com.vaadin.server.SerializablePredicate;
-
-public class InMemoryHierarchicalDataProviderTest extends
-        DataProviderTestBase<InMemoryHierarchicalDataProvider<StrBean>> {
-
-    private HierarchyData<StrBean> data;
-    private List<StrBean> flattenedData;
-    private List<StrBean> rootData;
-
-    @Override
-    public void setUp() {
-        List<StrBean> randomBeans = StrBean.generateRandomBeans(20);
-        flattenedData = new ArrayList<>();
-        rootData = new ArrayList<>();
-
-        data = new HierarchyData<>();
-        data.addItems(null, randomBeans.subList(0, 5));
-        data.addItems(randomBeans.get(0), randomBeans.subList(5, 10));
-        data.addItems(randomBeans.get(5), randomBeans.subList(10, 15));
-        data.addItems(null, randomBeans.subList(15, 20));
-
-        flattenedData.add(randomBeans.get(0));
-        flattenedData.add(randomBeans.get(5));
-        flattenedData.addAll(randomBeans.subList(10, 15));
-        flattenedData.addAll(randomBeans.subList(6, 10));
-        flattenedData.addAll(randomBeans.subList(1, 5));
-        flattenedData.addAll(randomBeans.subList(15, 20));
-
-        rootData.addAll(randomBeans.subList(0, 5));
-        rootData.addAll(randomBeans.subList(15, 20));
-
-        super.setUp();
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void hierarchyData_add_item_parent_not_in_hierarchy_throws() {
-        new HierarchyData<>().addItem(new StrBean("", 0, 0),
-                new StrBean("", 0, 0));
-    }
-
-    @Test(expected = NullPointerException.class)
-    public void hierarchyData_add_null_item_throws() {
-        new HierarchyData<>().addItem(null, null);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void hierarchyData_add_item_already_in_hierarchy_throws() {
-        StrBean bean = new StrBean("", 0, 0);
-        new HierarchyData<>().addItem(null, bean).addItem(null, bean);
-    }
-
-    @Test
-    public void hierarchyData_remove_root_item() {
-        data.removeItem(null);
-        Assert.assertTrue(data.getChildren(null).isEmpty());
-    }
-
-    @Test
-    public void hierarchyData_clear() {
-        data.clear();
-        Assert.assertTrue(data.getChildren(null).isEmpty());
-    }
-
-    @Test
-    public void hierarchyData_re_add_removed_item() {
-        StrBean item = rootData.get(0);
-        data.removeItem(item).addItem(null, item);
-        Assert.assertTrue(data.getChildren(null).contains(item));
-    }
-
-    @Test
-    public void setFilter() {
-        getDataProvider().setFilter(item -> item.getValue().equals("Xyz")
-                || item.getValue().equals("Baz"));
-
-        Assert.assertEquals(10, sizeWithUnfilteredQuery());
-
-        getDataProvider().setFilter(item -> !item.getValue().equals("Foo")
-                && !item.getValue().equals("Xyz"));
-
-        Assert.assertEquals(
-                "Previous filter should be replaced when setting a new one", 6,
-                sizeWithUnfilteredQuery());
-
-        getDataProvider().setFilter(null);
-
-        Assert.assertEquals("Setting filter to null should remove all filters",
-                20, sizeWithUnfilteredQuery());
-    }
-
-    @Test
-    public void addFilter() {
-        getDataProvider().addFilter(item -> item.getId() <= 10);
-        getDataProvider().addFilter(item -> item.getId() >= 5);
-        Assert.assertEquals(5, sizeWithUnfilteredQuery());
-    }
-
-    @Override
-    public void filteringListDataProvider_convertFilter() {
-        DataProvider<StrBean, String> strFilterDataProvider = getDataProvider()
-                .withConvertedFilter(
-                        text -> strBean -> strBean.getValue().contains(text));
-        Assert.assertEquals("Only one item should match 'Xyz'", 1,
-                strFilterDataProvider
-                        .size(new HierarchicalQuery<>("Xyz", null)));
-        Assert.assertEquals("No item should match 'Zyx'", 0,
-                strFilterDataProvider
-                        .size(new HierarchicalQuery<>("Zyx", null)));
-        Assert.assertEquals("Unexpected number of matches for 'Foo'", 3,
-                strFilterDataProvider
-                        .size(new HierarchicalQuery<>("Foo", null)));
-        Assert.assertEquals("No items should've been filtered out",
-                rootData.size(), strFilterDataProvider
-                        .size(new HierarchicalQuery<>(null, null)));
-    }
-
-    @Override
-    public void filteringListDataProvider_defaultFilterType() {
-        Assert.assertEquals("Only one item should match 'Xyz'", 1,
-                getDataProvider().size(new HierarchicalQuery<>(
-                        strBean -> strBean.getValue().contains("Xyz"), null)));
-        Assert.assertEquals("No item should match 'Zyx'", 0,
-                dataProvider.size(new HierarchicalQuery<>(
-                        strBean -> strBean.getValue().contains("Zyx"), null)));
-        Assert.assertEquals("Unexpected number of matches for 'Foo'", 3,
-                getDataProvider()
-                        .size(new HierarchicalQuery<>(fooFilter, null)));
-    }
-
-    @Override
-    public void testDefaultSortWithSpecifiedPostSort() {
-        Comparator<StrBean> comp = Comparator.comparing(StrBean::getValue)
-                .thenComparing(Comparator.comparing(StrBean::getId).reversed());
-        setSortOrder(QuerySortOrder.asc("value").thenDesc("id").build(), comp);
-
-        List<StrBean> list = getDataProvider()
-                .fetch(createQuery(QuerySortOrder.asc("randomNumber").build(),
-                        Comparator.comparing(StrBean::getRandomNumber), null,
-                        null))
-                .collect(Collectors.toList());
-
-        Assert.assertEquals("Sorted data and original data sizes don't match",
-                getDataProvider().fetch(new HierarchicalQuery<>(null, null))
-                        .count(),
-                list.size());
-
-        for (int i = 1; i < list.size(); ++i) {
-            StrBean prev = list.get(i - 1);
-            StrBean cur = list.get(i);
-            // Test specific sort
-            Assert.assertTrue(
-                    "Failure: " + prev.getRandomNumber() + " > "
-                            + cur.getRandomNumber(),
-                    prev.getRandomNumber() <= cur.getRandomNumber());
-
-            if (prev.getRandomNumber() == cur.getRandomNumber()) {
-                // Test default sort
-                Assert.assertTrue(
-                        prev.getValue().compareTo(cur.getValue()) <= 0);
-                if (prev.getValue().equals(cur.getValue())) {
-                    Assert.assertTrue(prev.getId() > cur.getId());
-                }
-            }
-        }
-    }
-
-    @Override
-    public void testDefaultSortWithFunction() {
-        setSortOrder(QuerySortOrder.asc("value").build(),
-                Comparator.comparing(StrBean::getValue));
-
-        List<StrBean> list = getDataProvider()
-                .fetch(new HierarchicalQuery<>(null, null))
-                .collect(Collectors.toList());
-
-        Assert.assertEquals("Sorted data and original data sizes don't match",
-                rootData.size(), list.size());
-
-        for (int i = 1; i < list.size(); ++i) {
-            StrBean prev = list.get(i - 1);
-            StrBean cur = list.get(i);
-
-            // Test default sort
-            Assert.assertTrue(prev.getValue().compareTo(cur.getValue()) <= 0);
-        }
-    }
-
-    @Override
-    public void testListContainsAllData() {
-        assertHierarchyCorrect();
-    }
-
-    @Override
-    public void testSortByComparatorListsDiffer() {
-        Comparator<StrBean> comp = Comparator.comparing(StrBean::getValue)
-                .thenComparing(StrBean::getRandomNumber)
-                .thenComparing(StrBean::getId);
-
-        List<StrBean> list = getDataProvider().fetch(
-                createQuery(QuerySortOrder.asc("value").thenAsc("randomNumber")
-                        .thenAsc("id").build(), comp, null, null))
-                .collect(Collectors.toList());
-
-        Assert.assertNotEquals("First value should not match", rootData.get(0),
-                list.get(0));
-
-        Assert.assertEquals("Sorted data and original data sizes don't match",
-                rootData.size(), list.size());
-
-        rootData.sort(comp);
-        for (int i = 0; i < rootData.size(); ++i) {
-            Assert.assertEquals("Sorting result differed", rootData.get(i),
-                    list.get(i));
-        }
-    }
-
-    @Override
-    protected InMemoryHierarchicalDataProvider<StrBean> createDataProvider() {
-        return new InMemoryHierarchicalDataProvider<>(data);
-    }
-
-    @Override
-    protected void setSortOrder(List<QuerySortOrder> sortOrder,
-            Comparator<StrBean> comp) {
-        getDataProvider().setSortComparator(comp::compare);
-    }
-
-    @Override
-    protected long sizeWithUnfilteredQuery() {
-        return getFlattenedDataFromProvider(new ArrayList<>(), null).size();
-    }
-
-    private void assertHierarchyCorrect() {
-        Assert.assertEquals(flattenedData,
-                getFlattenedData(new ArrayList<>(), null));
-        Assert.assertEquals(flattenedData,
-                getFlattenedDataFromProvider(new ArrayList<>(), null));
-    }
-
-    private List<StrBean> getFlattenedData(List<StrBean> flattened,
-            StrBean item) {
-        if (item != null) {
-            flattened.add(item);
-        }
-        data.getChildren(item)
-                .forEach(child -> getFlattenedData(flattened, child));
-        return flattened;
-    }
-
-    private List<StrBean> getFlattenedDataFromProvider(List<StrBean> flattened,
-            StrBean item) {
-        if (item != null) {
-            flattened.add(item);
-        }
-        getDataProvider().fetchChildren(new HierarchicalQuery<>(null, item))
-                .forEach(child -> getFlattenedDataFromProvider(flattened,
-                        child));
-        return flattened;
-    }
-
-    private HierarchicalQuery<StrBean, SerializablePredicate<StrBean>> createQuery(
-            List<QuerySortOrder> sortOrder, Comparator<StrBean> comp,
-            SerializablePredicate<StrBean> filter, StrBean parent) {
-        return new HierarchicalQuery<>(0, Integer.MAX_VALUE, sortOrder, comp,
-                filter, parent);
-    }
-}
diff --git a/server/src/test/java/com/vaadin/data/provider/TreeDataProviderTest.java b/server/src/test/java/com/vaadin/data/provider/TreeDataProviderTest.java
new file mode 100644 (file)
index 0000000..3f9f1f6
--- /dev/null
@@ -0,0 +1,297 @@
+package com.vaadin.data.provider;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.vaadin.data.TreeData;
+import com.vaadin.server.SerializablePredicate;
+
+public class TreeDataProviderTest extends
+        DataProviderTestBase<TreeDataProvider<StrBean>> {
+
+    private TreeData<StrBean> data;
+    private List<StrBean> flattenedData;
+    private List<StrBean> rootData;
+
+    @Override
+    public void setUp() {
+        List<StrBean> randomBeans = StrBean.generateRandomBeans(20);
+        flattenedData = new ArrayList<>();
+        rootData = new ArrayList<>();
+
+        data = new TreeData<>();
+        data.addItems(null, randomBeans.subList(0, 5));
+        data.addItems(randomBeans.get(0), randomBeans.subList(5, 10));
+        data.addItems(randomBeans.get(5), randomBeans.subList(10, 15));
+        data.addItems(null, randomBeans.subList(15, 20));
+
+        flattenedData.add(randomBeans.get(0));
+        flattenedData.add(randomBeans.get(5));
+        flattenedData.addAll(randomBeans.subList(10, 15));
+        flattenedData.addAll(randomBeans.subList(6, 10));
+        flattenedData.addAll(randomBeans.subList(1, 5));
+        flattenedData.addAll(randomBeans.subList(15, 20));
+
+        rootData.addAll(randomBeans.subList(0, 5));
+        rootData.addAll(randomBeans.subList(15, 20));
+
+        super.setUp();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void treeData_add_item_parent_not_in_hierarchy_throws() {
+        new TreeData<>().addItem(new StrBean("", 0, 0),
+                new StrBean("", 0, 0));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void treeData_add_null_item_throws() {
+        new TreeData<>().addItem(null, null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void treeData_add_item_already_in_hierarchy_throws() {
+        StrBean bean = new StrBean("", 0, 0);
+        new TreeData<>().addItem(null, bean).addItem(null, bean);
+    }
+
+    @Test
+    public void treeData_remove_root_item() {
+        data.removeItem(null);
+        Assert.assertTrue(data.getChildren(null).isEmpty());
+    }
+
+    @Test
+    public void treeData_clear() {
+        data.clear();
+        Assert.assertTrue(data.getChildren(null).isEmpty());
+    }
+
+    @Test
+    public void treeData_re_add_removed_item() {
+        StrBean item = rootData.get(0);
+        data.removeItem(item).addItem(null, item);
+        Assert.assertTrue(data.getChildren(null).contains(item));
+    }
+
+    @Test
+    public void populate_treeData_with_child_item_provider() {
+        TreeData<String> stringData = new TreeData<>();
+        List<String> rootItems = Arrays.asList("a", "b", "c");
+        stringData.addItems(rootItems, item -> {
+            if (item.length() >= 3 || item.startsWith("c")) {
+                return Arrays.asList();
+            }
+            return Arrays.asList(item + "/a", item + "/b", item + "/c");
+        });
+        Assert.assertEquals(stringData.getChildren("a"),
+                Arrays.asList("a/a", "a/b", "a/c"));
+        Assert.assertEquals(stringData.getChildren("b"),
+                Arrays.asList("b/a", "b/b", "b/c"));
+        Assert.assertEquals(stringData.getChildren("c"), Arrays.asList());
+        Assert.assertEquals(stringData.getChildren("a/b"), Arrays.asList());
+    }
+
+    @Test
+    public void setFilter() {
+        getDataProvider().setFilter(item -> item.getValue().equals("Xyz")
+                || item.getValue().equals("Baz"));
+
+        Assert.assertEquals(10, sizeWithUnfilteredQuery());
+
+        getDataProvider().setFilter(item -> !item.getValue().equals("Foo")
+                && !item.getValue().equals("Xyz"));
+
+        Assert.assertEquals(
+                "Previous filter should be replaced when setting a new one", 6,
+                sizeWithUnfilteredQuery());
+
+        getDataProvider().setFilter(null);
+
+        Assert.assertEquals("Setting filter to null should remove all filters",
+                20, sizeWithUnfilteredQuery());
+    }
+
+    @Test
+    public void addFilter() {
+        getDataProvider().addFilter(item -> item.getId() <= 10);
+        getDataProvider().addFilter(item -> item.getId() >= 5);
+        Assert.assertEquals(5, sizeWithUnfilteredQuery());
+    }
+
+    @Override
+    public void filteringListDataProvider_convertFilter() {
+        DataProvider<StrBean, String> strFilterDataProvider = getDataProvider()
+                .withConvertedFilter(
+                        text -> strBean -> strBean.getValue().contains(text));
+        Assert.assertEquals("Only one item should match 'Xyz'", 1,
+                strFilterDataProvider
+                        .size(new HierarchicalQuery<>("Xyz", null)));
+        Assert.assertEquals("No item should match 'Zyx'", 0,
+                strFilterDataProvider
+                        .size(new HierarchicalQuery<>("Zyx", null)));
+        Assert.assertEquals("Unexpected number of matches for 'Foo'", 3,
+                strFilterDataProvider
+                        .size(new HierarchicalQuery<>("Foo", null)));
+        Assert.assertEquals("No items should've been filtered out",
+                rootData.size(), strFilterDataProvider
+                        .size(new HierarchicalQuery<>(null, null)));
+    }
+
+    @Override
+    public void filteringListDataProvider_defaultFilterType() {
+        Assert.assertEquals("Only one item should match 'Xyz'", 1,
+                getDataProvider().size(new HierarchicalQuery<>(
+                        strBean -> strBean.getValue().contains("Xyz"), null)));
+        Assert.assertEquals("No item should match 'Zyx'", 0,
+                dataProvider.size(new HierarchicalQuery<>(
+                        strBean -> strBean.getValue().contains("Zyx"), null)));
+        Assert.assertEquals("Unexpected number of matches for 'Foo'", 3,
+                getDataProvider()
+                        .size(new HierarchicalQuery<>(fooFilter, null)));
+    }
+
+    @Override
+    public void testDefaultSortWithSpecifiedPostSort() {
+        Comparator<StrBean> comp = Comparator.comparing(StrBean::getValue)
+                .thenComparing(Comparator.comparing(StrBean::getId).reversed());
+        setSortOrder(QuerySortOrder.asc("value").thenDesc("id").build(), comp);
+
+        List<StrBean> list = getDataProvider()
+                .fetch(createQuery(QuerySortOrder.asc("randomNumber").build(),
+                        Comparator.comparing(StrBean::getRandomNumber), null,
+                        null))
+                .collect(Collectors.toList());
+
+        Assert.assertEquals("Sorted data and original data sizes don't match",
+                getDataProvider().fetch(new HierarchicalQuery<>(null, null))
+                        .count(),
+                list.size());
+
+        for (int i = 1; i < list.size(); ++i) {
+            StrBean prev = list.get(i - 1);
+            StrBean cur = list.get(i);
+            // Test specific sort
+            Assert.assertTrue(
+                    "Failure: " + prev.getRandomNumber() + " > "
+                            + cur.getRandomNumber(),
+                    prev.getRandomNumber() <= cur.getRandomNumber());
+
+            if (prev.getRandomNumber() == cur.getRandomNumber()) {
+                // Test default sort
+                Assert.assertTrue(
+                        prev.getValue().compareTo(cur.getValue()) <= 0);
+                if (prev.getValue().equals(cur.getValue())) {
+                    Assert.assertTrue(prev.getId() > cur.getId());
+                }
+            }
+        }
+    }
+
+    @Override
+    public void testDefaultSortWithFunction() {
+        setSortOrder(QuerySortOrder.asc("value").build(),
+                Comparator.comparing(StrBean::getValue));
+
+        List<StrBean> list = getDataProvider()
+                .fetch(new HierarchicalQuery<>(null, null))
+                .collect(Collectors.toList());
+
+        Assert.assertEquals("Sorted data and original data sizes don't match",
+                rootData.size(), list.size());
+
+        for (int i = 1; i < list.size(); ++i) {
+            StrBean prev = list.get(i - 1);
+            StrBean cur = list.get(i);
+
+            // Test default sort
+            Assert.assertTrue(prev.getValue().compareTo(cur.getValue()) <= 0);
+        }
+    }
+
+    @Override
+    public void testListContainsAllData() {
+        assertHierarchyCorrect();
+    }
+
+    @Override
+    public void testSortByComparatorListsDiffer() {
+        Comparator<StrBean> comp = Comparator.comparing(StrBean::getValue)
+                .thenComparing(StrBean::getRandomNumber)
+                .thenComparing(StrBean::getId);
+
+        List<StrBean> list = getDataProvider().fetch(
+                createQuery(QuerySortOrder.asc("value").thenAsc("randomNumber")
+                        .thenAsc("id").build(), comp, null, null))
+                .collect(Collectors.toList());
+
+        Assert.assertNotEquals("First value should not match", rootData.get(0),
+                list.get(0));
+
+        Assert.assertEquals("Sorted data and original data sizes don't match",
+                rootData.size(), list.size());
+
+        rootData.sort(comp);
+        for (int i = 0; i < rootData.size(); ++i) {
+            Assert.assertEquals("Sorting result differed", rootData.get(i),
+                    list.get(i));
+        }
+    }
+
+    @Override
+    protected TreeDataProvider<StrBean> createDataProvider() {
+        return new TreeDataProvider<>(data);
+    }
+
+    @Override
+    protected void setSortOrder(List<QuerySortOrder> sortOrder,
+            Comparator<StrBean> comp) {
+        getDataProvider().setSortComparator(comp::compare);
+    }
+
+    @Override
+    protected long sizeWithUnfilteredQuery() {
+        return getFlattenedDataFromProvider(new ArrayList<>(), null).size();
+    }
+
+    private void assertHierarchyCorrect() {
+        Assert.assertEquals(flattenedData,
+                getFlattenedData(new ArrayList<>(), null));
+        Assert.assertEquals(flattenedData,
+                getFlattenedDataFromProvider(new ArrayList<>(), null));
+    }
+
+    private List<StrBean> getFlattenedData(List<StrBean> flattened,
+            StrBean item) {
+        if (item != null) {
+            flattened.add(item);
+        }
+        data.getChildren(item)
+                .forEach(child -> getFlattenedData(flattened, child));
+        return flattened;
+    }
+
+    private List<StrBean> getFlattenedDataFromProvider(List<StrBean> flattened,
+            StrBean item) {
+        if (item != null) {
+            flattened.add(item);
+        }
+        getDataProvider().fetchChildren(new HierarchicalQuery<>(null, item))
+                .forEach(child -> getFlattenedDataFromProvider(flattened,
+                        child));
+        return flattened;
+    }
+
+    private HierarchicalQuery<StrBean, SerializablePredicate<StrBean>> createQuery(
+            List<QuerySortOrder> sortOrder, Comparator<StrBean> comp,
+            SerializablePredicate<StrBean> filter, StrBean parent) {
+        return new HierarchicalQuery<>(0, Integer.MAX_VALUE, sortOrder, comp,
+                filter, parent);
+    }
+}
index 13ef0acc497fee7ec95a1b09769bf228e2e7b205..9224934a4cb76a5fac4ad301b7d97b7db4b67c49 100644 (file)
@@ -3,8 +3,8 @@ package com.vaadin.tests.components;
 import org.junit.Assert;
 import org.junit.Test;
 
-import com.vaadin.data.HierarchyData;
-import com.vaadin.data.provider.InMemoryHierarchicalDataProvider;
+import com.vaadin.data.TreeData;
+import com.vaadin.data.provider.TreeDataProvider;
 import com.vaadin.event.CollapseEvent;
 import com.vaadin.event.CollapseEvent.CollapseListener;
 import com.vaadin.event.ExpandEvent;
@@ -52,12 +52,12 @@ public class TreeTest {
     @Test
     public void event_source_is_tree() {
         Tree<String> tree = new Tree<>();
-        HierarchyData<String> hierarchyData = new HierarchyData<>();
-        hierarchyData.addItem(null, "Foo");
-        hierarchyData.addItem("Foo", "Bar");
-        hierarchyData.addItem("Foo", "Baz");
+        TreeData<String> treeData = new TreeData<>();
+        treeData.addItem(null, "Foo");
+        treeData.addItem("Foo", "Bar");
+        treeData.addItem("Foo", "Baz");
         tree.setDataProvider(
-                new InMemoryHierarchicalDataProvider<>(hierarchyData));
+                new TreeDataProvider<>(treeData));
 
         TreeCollapseExpandListener listener = new TreeCollapseExpandListener(
                 tree);
index 2e335f865ea7eca84676a821ba50a34118d736ff..1544a4f69dd3a0993ae3b3dd7a165315069393e1 100644 (file)
@@ -3,8 +3,8 @@ package com.vaadin.tests.components.treegrid;
 import org.junit.Assert;
 import org.junit.Test;
 
-import com.vaadin.data.HierarchyData;
-import com.vaadin.data.provider.InMemoryHierarchicalDataProvider;
+import com.vaadin.data.TreeData;
+import com.vaadin.data.provider.TreeDataProvider;
 import com.vaadin.ui.TreeGrid;
 import com.vaadin.ui.renderers.TextRenderer;
 
@@ -24,12 +24,12 @@ public class TreeGridTest {
 
     @Test
     public void testExpandAndCollapseEvents() {
-        HierarchyData<String> hierarchyData = new HierarchyData<>();
-        hierarchyData.addItem(null, "Foo");
-        hierarchyData.addItem("Foo", "Bar");
-        hierarchyData.addItem("Foo", "Baz");
+        TreeData<String> treeData = new TreeData<>();
+        treeData.addItem(null, "Foo");
+        treeData.addItem("Foo", "Bar");
+        treeData.addItem("Foo", "Baz");
         treeGrid.setDataProvider(
-                new InMemoryHierarchicalDataProvider<>(hierarchyData));
+                new TreeDataProvider<>(treeData));
 
         treeGrid.addExpandListener(e -> expandEventFired = true);
         treeGrid.addCollapseListener(e -> collapseEventFired = true);
index b4f985186700b8abe7fcf689c262a80522f49eaa..d2d25b477720586c6c124f9e5437b5b591f192d6 100644 (file)
@@ -76,6 +76,7 @@ public class ClassesSerializableTest {
             "com\\.vaadin\\.buildhelpers.*", //
             "com\\.vaadin\\.util\\.EncodeUtil.*", //
             "com\\.vaadin\\.util\\.ReflectTools.*", //
+            "com\\.vaadin\\.data\\.provider\\.InMemoryDataProviderHelpers",
             "com\\.vaadin\\.data\\.provider\\.HierarchyMapper\\$TreeLevelQuery",
             "com\\.vaadin\\.data\\.util\\.ReflectTools.*", //
             "com\\.vaadin\\.data\\.util\\.JsonUtil.*", //
index c8a51a1928e160be9d637113829e329bbfd06811..a13ba357effb16bb121d384372271e327afe12d0 100644 (file)
@@ -4,9 +4,9 @@ import java.lang.reflect.InvocationTargetException;
 
 import org.junit.Assert;
 
-import com.vaadin.data.HierarchyData;
+import com.vaadin.data.TreeData;
 import com.vaadin.data.provider.HierarchicalQuery;
-import com.vaadin.data.provider.InMemoryHierarchicalDataProvider;
+import com.vaadin.data.provider.TreeDataProvider;
 import com.vaadin.tests.data.bean.Person;
 import com.vaadin.tests.server.component.abstractlisting.AbstractListingDeclarativeTest;
 import com.vaadin.ui.TreeGrid;
@@ -28,7 +28,7 @@ public class TreeGridDeclarativeTest
         Person person6 = createPerson("ca", "last-name");
         Person person7 = createPerson("caa", "last-name");
 
-        HierarchyData<Person> data = new HierarchyData<>();
+        TreeData<Person> data = new TreeData<>();
         data.addItems(null, person1, person4, person5);
         data.addItems(person1, person2, person3);
         data.addItem(person5, person6);
@@ -38,7 +38,7 @@ public class TreeGridDeclarativeTest
         grid.addColumn(Person::getLastName).setId("id").setCaption("Id");
 
         grid.setHierarchyColumn("id");
-        grid.setDataProvider(new InMemoryHierarchicalDataProvider<>(data));
+        grid.setDataProvider(new TreeDataProvider<>(data));
 
         String design = String.format(
                 "<%s hierarchy-column='id'><table><colgroup>"
index e0fa469fa8d488fe07b251cb8af30dd59b3884de..a579c98a12c428761d48137e736cb6806d5c1ea9 100644 (file)
@@ -5,8 +5,8 @@ import java.util.List;
 
 import com.vaadin.annotations.Theme;
 import com.vaadin.annotations.Widgetset;
-import com.vaadin.data.HierarchyData;
-import com.vaadin.data.provider.InMemoryHierarchicalDataProvider;
+import com.vaadin.data.TreeData;
+import com.vaadin.data.provider.TreeDataProvider;
 import com.vaadin.icons.VaadinIcons;
 import com.vaadin.server.ClassResource;
 import com.vaadin.server.ThemeResource;
@@ -27,7 +27,7 @@ import com.vaadin.ui.VerticalLayout;
 public class TreeBasicFeatures extends AbstractTestUIWithLog {
 
     private Tree<HierarchicalTestBean> tree;
-    private InMemoryHierarchicalDataProvider<HierarchicalTestBean> inMemoryDataProvider;
+    private TreeDataProvider<HierarchicalTestBean> inMemoryDataProvider;
     private IconGenerator<HierarchicalTestBean> iconGenerator = i -> {
         switch (i.getDepth()) {
         case 0:
@@ -126,7 +126,7 @@ public class TreeBasicFeatures extends AbstractTestUIWithLog {
     }
 
     private void setupDataProvider() {
-        HierarchyData<HierarchicalTestBean> data = new HierarchyData<>();
+        TreeData<HierarchicalTestBean> data = new TreeData<>();
 
         List<Integer> ints = Arrays.asList(0, 1, 2);
 
@@ -145,7 +145,7 @@ public class TreeBasicFeatures extends AbstractTestUIWithLog {
             });
         });
 
-        inMemoryDataProvider = new InMemoryHierarchicalDataProvider<>(data);
+        inMemoryDataProvider = new TreeDataProvider<>(data);
     }
 
 }
index 8151aa8c8876ab90686ec19fac6d95f1e907bf63..13064c4c3991eb0abb624c952874e7d2c6de0538 100644 (file)
@@ -8,11 +8,11 @@ import java.util.stream.Stream;
 
 import com.vaadin.annotations.Theme;
 import com.vaadin.annotations.Widgetset;
-import com.vaadin.data.HierarchyData;
+import com.vaadin.data.TreeData;
 import com.vaadin.data.provider.DataProvider;
 import com.vaadin.data.provider.HierarchicalDataProvider;
 import com.vaadin.data.provider.HierarchicalQuery;
-import com.vaadin.data.provider.InMemoryHierarchicalDataProvider;
+import com.vaadin.data.provider.TreeDataProvider;
 import com.vaadin.server.SerializablePredicate;
 import com.vaadin.shared.Range;
 import com.vaadin.tests.components.AbstractComponentTest;
@@ -24,7 +24,7 @@ import com.vaadin.ui.TreeGrid;
 public class TreeGridBasicFeatures extends AbstractComponentTest<TreeGrid> {
 
     private TreeGrid<HierarchicalTestBean> grid;
-    private InMemoryHierarchicalDataProvider<HierarchicalTestBean> inMemoryDataProvider;
+    private TreeDataProvider<HierarchicalTestBean> inMemoryDataProvider;
     private LazyHierarchicalDataProvider lazyDataProvider;
     private HierarchicalDataProvider<HierarchicalTestBean, ?> loggingDataProvider;
 
@@ -70,7 +70,7 @@ public class TreeGridBasicFeatures extends AbstractComponentTest<TreeGrid> {
     }
 
     private void initializeDataProviders() {
-        HierarchyData<HierarchicalTestBean> data = new HierarchyData<>();
+        TreeData<HierarchicalTestBean> data = new TreeData<>();
 
         List<Integer> ints = Arrays.asList(0, 1, 2);
 
@@ -89,9 +89,9 @@ public class TreeGridBasicFeatures extends AbstractComponentTest<TreeGrid> {
             });
         });
 
-        inMemoryDataProvider = new InMemoryHierarchicalDataProvider<>(data);
+        inMemoryDataProvider = new TreeDataProvider<>(data);
         lazyDataProvider = new LazyHierarchicalDataProvider(3, 2);
-        loggingDataProvider = new InMemoryHierarchicalDataProvider<HierarchicalTestBean>(
+        loggingDataProvider = new TreeDataProvider<HierarchicalTestBean>(
                 data) {
 
             @Override
@@ -118,7 +118,7 @@ public class TreeGridBasicFeatures extends AbstractComponentTest<TreeGrid> {
         @SuppressWarnings("rawtypes")
         LinkedHashMap<String, DataProvider> options = new LinkedHashMap<>();
         options.put("LazyHierarchicalDataProvider", lazyDataProvider);
-        options.put("InMemoryHierarchicalDataProvider", inMemoryDataProvider);
+        options.put("TreeDataProvider", inMemoryDataProvider);
         options.put("LoggingDataProvider", loggingDataProvider);
 
         createSelectAction("Set data provider", CATEGORY_FEATURES, options,
index c7943524e497a41d47de967b152be13a5a407f01..d630e3629268ccf2dbd2c66baf2648c751863e48 100644 (file)
@@ -2,10 +2,10 @@ package com.vaadin.tests.components.treegrid;
 
 import java.util.stream.Stream;
 
-import com.vaadin.data.HierarchyData;
+import com.vaadin.data.TreeData;
 import com.vaadin.data.ValueProvider;
 import com.vaadin.data.provider.HierarchicalQuery;
-import com.vaadin.data.provider.InMemoryHierarchicalDataProvider;
+import com.vaadin.data.provider.TreeDataProvider;
 import com.vaadin.server.SerializablePredicate;
 import com.vaadin.server.VaadinRequest;
 import com.vaadin.tests.components.AbstractTestUI;
@@ -15,18 +15,18 @@ import com.vaadin.ui.TreeGrid;
 public class TreeGridChangingHierarchy extends AbstractTestUI {
 
     private static class TestDataProvider
-            extends InMemoryHierarchicalDataProvider<String> {
+            extends TreeDataProvider<String> {
 
-        private HierarchyData<String> hierarchyData;
+        private TreeData<String> treeData;
 
-        public TestDataProvider(HierarchyData<String> hierarchyData) {
-            super(hierarchyData);
-            this.hierarchyData = hierarchyData;
+        public TestDataProvider(TreeData<String> treeData) {
+            super(treeData);
+            this.treeData = treeData;
         }
 
         @Override
         public boolean hasChildren(String item) {
-            if (!hierarchyData.contains(item)) {
+            if (!treeData.contains(item)) {
                 return false;
             }
             return super.hasChildren(item);
@@ -35,7 +35,7 @@ public class TreeGridChangingHierarchy extends AbstractTestUI {
         @Override
         public Stream<String> fetchChildren(
                 HierarchicalQuery<String, SerializablePredicate<String>> query) {
-            if (!hierarchyData.contains(query.getParent())) {
+            if (!treeData.contains(query.getParent())) {
                 return Stream.empty();
             }
             return super.fetchChildren(query);
@@ -44,7 +44,7 @@ public class TreeGridChangingHierarchy extends AbstractTestUI {
 
     @Override
     protected void setup(VaadinRequest request) {
-        HierarchyData<String> data = new HierarchyData<>();
+        TreeData<String> data = new TreeData<>();
         data.addItems(null, "a", "b", "c").addItem("b", "b/a");
 
         TreeGrid<String> grid = new TreeGrid<>();
index 7cfb9268497207a761156e9fae2f2cc15f8a1dd5..f56052400e4ace4f054d5dc8414c523a76a877cd 100644 (file)
@@ -2,8 +2,8 @@ package com.vaadin.tests.components.treegrid;
 
 import com.vaadin.annotations.Theme;
 import com.vaadin.annotations.Widgetset;
-import com.vaadin.data.HierarchyData;
-import com.vaadin.data.provider.InMemoryHierarchicalDataProvider;
+import com.vaadin.data.TreeData;
+import com.vaadin.data.provider.TreeDataProvider;
 import com.vaadin.server.VaadinRequest;
 import com.vaadin.tests.components.AbstractTestUI;
 import com.vaadin.ui.Button;
@@ -15,10 +15,10 @@ public class TreeGridHugeTree
         extends AbstractTestUI {
 
     private TreeGrid<String> treeGrid;
-    private InMemoryHierarchicalDataProvider<String> inMemoryDataProvider;
+    private TreeDataProvider<String> inMemoryDataProvider;
 
     private void initializeDataProvider() {
-        HierarchyData<String> data = new HierarchyData<>();
+        TreeData<String> data = new TreeData<>();
         for (int i = 0; i < 3; i++) {
             String granddad = "Granddad " + i;
             data.addItem(null, granddad);
@@ -31,7 +31,7 @@ public class TreeGridHugeTree
                 }
             }
         }
-        inMemoryDataProvider = new InMemoryHierarchicalDataProvider<>(data);
+        inMemoryDataProvider = new TreeDataProvider<>(data);
     }
 
     @Override
index fc550a95703c985c7f6775b69db62e2a9f220e49..02bfd65a289ac0e3103dd0c1612eac09f83b8f35 100644 (file)
@@ -2,8 +2,8 @@ package com.vaadin.tests.components.treegrid;
 
 import com.vaadin.annotations.Theme;
 import com.vaadin.annotations.Widgetset;
-import com.vaadin.data.HierarchyData;
-import com.vaadin.data.provider.InMemoryHierarchicalDataProvider;
+import com.vaadin.data.TreeData;
+import com.vaadin.data.provider.TreeDataProvider;
 import com.vaadin.tests.components.AbstractComponentTest;
 import com.vaadin.ui.TreeGrid;
 
@@ -12,7 +12,7 @@ import com.vaadin.ui.TreeGrid;
 public class TreeGridHugeTreeNavigation extends AbstractComponentTest<TreeGrid> {
 
     private TreeGrid<String> treeGrid;
-    private InMemoryHierarchicalDataProvider<String> inMemoryDataProvider;
+    private TreeDataProvider<String> inMemoryDataProvider;
 
     @Override
     public TreeGrid getComponent() {
@@ -40,7 +40,7 @@ public class TreeGridHugeTreeNavigation extends AbstractComponentTest<TreeGrid>
     }
 
     private void initializeDataProvider() {
-        HierarchyData<String> data = new HierarchyData<>();
+        TreeData<String> data = new TreeData<>();
         for (int i = 0; i < 3; i++) {
             String granddad = "Granddad " + i;
             data.addItem(null, granddad);
@@ -53,7 +53,7 @@ public class TreeGridHugeTreeNavigation extends AbstractComponentTest<TreeGrid>
                 }
             }
         }
-        inMemoryDataProvider = new InMemoryHierarchicalDataProvider<>(data);
+        inMemoryDataProvider = new TreeDataProvider<>(data);
     }
 
 }
index db5b8c54b6002d92c20c09f39bfdd710bc166cd5..4c4b95c3d18ec1610a980da79ae24eb20efed72c 100644 (file)
@@ -1,7 +1,7 @@
 package com.vaadin.tests.components.treegrid;
 
-import com.vaadin.data.HierarchyData;
-import com.vaadin.data.provider.InMemoryHierarchicalDataProvider;
+import com.vaadin.data.TreeData;
+import com.vaadin.data.provider.TreeDataProvider;
 import com.vaadin.server.VaadinRequest;
 import com.vaadin.tests.components.AbstractTestUI;
 import com.vaadin.ui.TreeGrid;
@@ -13,13 +13,13 @@ public class TreeGridInitialExpand extends AbstractTestUI {
         TreeGrid<String> treeGrid = new TreeGrid<>();
         treeGrid.setCaption("Test");
         treeGrid.addColumn(String::toString).setCaption("String");
-        HierarchyData<String> data = new HierarchyData<>();
+        TreeData<String> data = new TreeData<>();
         data.addItem(null, "parent1");
         data.addItem("parent1", "parent1-child1");
         data.addItem("parent1", "parent1-child2");
         data.addItem(null, "parent2");
         data.addItem("parent2", "parent2-child2");
-        treeGrid.setDataProvider(new InMemoryHierarchicalDataProvider<>(data));
+        treeGrid.setDataProvider(new TreeDataProvider<>(data));
         treeGrid.setHeightByRows(5);
         treeGrid.expand("parent1");
         treeGrid.expand("parent2");
index 531cd8e283c0c29f2718954dcb88ab2cb381a6c8..3f4047e4572bcd3f3ad1c77cfdc1d290b596a936 100644 (file)
@@ -7,8 +7,8 @@ import java.util.Optional;
 import javax.servlet.annotation.WebServlet;
 
 import com.vaadin.annotations.VaadinServletConfiguration;
-import com.vaadin.data.HierarchyData;
-import com.vaadin.data.provider.InMemoryHierarchicalDataProvider;
+import com.vaadin.data.TreeData;
+import com.vaadin.data.provider.TreeDataProvider;
 import com.vaadin.server.VaadinRequest;
 import com.vaadin.server.VaadinServlet;
 import com.vaadin.tests.data.bean.Address;
@@ -54,22 +54,22 @@ public class TreeGridMemory extends AbstractBeansMemoryTest<TreeGrid<Person>> {
     @Override
     protected void setInMemoryContainer(TreeGrid<Person> treeGrid,
             List<Person> data) {
-        HierarchyData<Person> hierarchyData = new HierarchyData<>();
+        TreeData<Person> treeData = new TreeData<>();
         treeGrid.setDataProvider(
-                new InMemoryHierarchicalDataProvider<>(hierarchyData));
+                new TreeDataProvider<>(treeData));
         List<Person> toExpand = new ArrayList<>();
         if (data.size() != 0 && data.size() % 2 == 0) {
             // treat list as if it were a balanced binary tree
-            hierarchyData.addItem(null, data.get(0));
+            treeData.addItem(null, data.get(0));
             int n = 0;
             while (2 * n + 2 < data.size()) {
-                hierarchyData.addItems(data.get(n),
+                treeData.addItems(data.get(n),
                         data.subList(2 * n + 1, 2 * n + 3));
                 toExpand.add(data.get(n));
                 n++;
             }
         } else {
-            hierarchyData.addItems(null, data);
+            treeData.addItems(null, data);
         }
         if (initiallyExpanded) {
             treeGrid.expand(toExpand);
index 18b320abba272d51920df0d8c867fc5d2b0bb1bd..a766490017b155f11cfd36d622604980a2b502d1 100644 (file)
@@ -32,7 +32,7 @@ public class TreeGridBasicFeaturesTest extends MultiBrowserTest {
     @Parameters
     public static Collection<String> getDataProviders() {
         return Arrays.asList("LazyHierarchicalDataProvider",
-                "InMemoryHierarchicalDataProvider");
+                "TreeDataProvider");
     }
 
     @Before
index 2000d1388bf04629e9b849e9176ca297cbe9cbe0..4e56e8445eff37a4c951e915d2e166f4aa0a5ba7 100644 (file)
@@ -19,7 +19,7 @@ public class TreeGridClientSortTest extends SingleBrowserTest {
         openTestURL();
         TreeGridElement grid = $(TreeGridElement.class).first();
         selectMenuPath("Component", "Features", "Set data provider",
-                "InMemoryHierarchicalDataProvider");
+                "TreeDataProvider");
         grid.getHeaderCell(0, 0).doubleClick();
         grid.expandWithClick(0);
         grid.expandWithClick(1);