* 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.
<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>
[[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
----
[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();
----
font-style: italic;
}
----
-////
\ No newline at end of file
+////
[[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
----
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);
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");
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());
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);
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());
=== 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);
----
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)`
** 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:
--- /dev/null
+/*
+ * 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));
+ }
+}
+++ /dev/null
-/*
- * 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);
- }
-}
--- /dev/null
+/*
+ * 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);
+ });
+ }
+}
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;
/**
* 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
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
+++ /dev/null
-/*
- * 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);
- }
-}
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.
* @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;
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();
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));
- });
- }
}
--- /dev/null
+/*
+ * 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);
+ }
+}
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;
* @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
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
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;
* @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<>());
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)) {
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"));
}
}
- setDataProvider(new InMemoryHierarchicalDataProvider<>(data));
+ setDataProvider(new TreeDataProvider<>(data));
selectedItems.forEach(getSelectionModel()::select);
}
+++ /dev/null
-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);
- }
-}
--- /dev/null
+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);
+ }
+}
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;
@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);
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;
@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);
"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.*", //
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;
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);
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>"
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;
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:
}
private void setupDataProvider() {
- HierarchyData<HierarchicalTestBean> data = new HierarchyData<>();
+ TreeData<HierarchicalTestBean> data = new TreeData<>();
List<Integer> ints = Arrays.asList(0, 1, 2);
});
});
- inMemoryDataProvider = new InMemoryHierarchicalDataProvider<>(data);
+ inMemoryDataProvider = new TreeDataProvider<>(data);
}
}
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;
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;
}
private void initializeDataProviders() {
- HierarchyData<HierarchicalTestBean> data = new HierarchyData<>();
+ TreeData<HierarchicalTestBean> data = new TreeData<>();
List<Integer> ints = Arrays.asList(0, 1, 2);
});
});
- inMemoryDataProvider = new InMemoryHierarchicalDataProvider<>(data);
+ inMemoryDataProvider = new TreeDataProvider<>(data);
lazyDataProvider = new LazyHierarchicalDataProvider(3, 2);
- loggingDataProvider = new InMemoryHierarchicalDataProvider<HierarchicalTestBean>(
+ loggingDataProvider = new TreeDataProvider<HierarchicalTestBean>(
data) {
@Override
@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,
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;
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);
@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);
@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<>();
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;
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);
}
}
}
- inMemoryDataProvider = new InMemoryHierarchicalDataProvider<>(data);
+ inMemoryDataProvider = new TreeDataProvider<>(data);
}
@Override
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;
public class TreeGridHugeTreeNavigation extends AbstractComponentTest<TreeGrid> {
private TreeGrid<String> treeGrid;
- private InMemoryHierarchicalDataProvider<String> inMemoryDataProvider;
+ private TreeDataProvider<String> inMemoryDataProvider;
@Override
public TreeGrid getComponent() {
}
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);
}
}
}
- inMemoryDataProvider = new InMemoryHierarchicalDataProvider<>(data);
+ inMemoryDataProvider = new TreeDataProvider<>(data);
}
}
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;
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");
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;
@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);
@Parameters
public static Collection<String> getDataProviders() {
return Arrays.asList("LazyHierarchicalDataProvider",
- "InMemoryHierarchicalDataProvider");
+ "TreeDataProvider");
}
@Before
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);