aboutsummaryrefslogtreecommitdiffstats
path: root/server/src/main/java
diff options
context:
space:
mode:
authorAleksi Hietanen <aleksi@vaadin.com>2017-05-16 11:57:02 +0300
committerPekka Hyvönen <pekka@vaadin.com>2017-05-16 11:57:02 +0300
commitefa7f5a4d069556061ba4ceef4fb4d76dae84ef4 (patch)
tree767b0fdb3146930919cec37e5eaab75422b0867d /server/src/main/java
parenteb743d965278d263a4c496bb4e39c067fe2b1a8c (diff)
downloadvaadin-framework-efa7f5a4d069556061ba4ceef4fb4d76dae84ef4.tar.gz
vaadin-framework-efa7f5a4d069556061ba4ceef4fb4d76dae84ef4.zip
Refactor common methods in in-memory data providers (#9308)
* 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.
Diffstat (limited to 'server/src/main/java')
-rw-r--r--server/src/main/java/com/vaadin/data/HasHierarchicalDataProvider.java207
-rw-r--r--server/src/main/java/com/vaadin/data/TreeData.java (renamed from server/src/main/java/com/vaadin/data/HierarchyData.java)47
-rw-r--r--server/src/main/java/com/vaadin/data/provider/HierarchicalDataCommunicator.java8
-rw-r--r--server/src/main/java/com/vaadin/data/provider/InMemoryDataProvider.java451
-rw-r--r--server/src/main/java/com/vaadin/data/provider/InMemoryDataProviderHelpers.java185
-rw-r--r--server/src/main/java/com/vaadin/data/provider/ListDataProvider.java471
-rw-r--r--server/src/main/java/com/vaadin/data/provider/TreeDataProvider.java (renamed from server/src/main/java/com/vaadin/data/provider/InMemoryHierarchicalDataProvider.java)129
-rw-r--r--server/src/main/java/com/vaadin/ui/Tree.java10
-rw-r--r--server/src/main/java/com/vaadin/ui/TreeGrid.java124
9 files changed, 937 insertions, 695 deletions
diff --git a/server/src/main/java/com/vaadin/data/HasHierarchicalDataProvider.java b/server/src/main/java/com/vaadin/data/HasHierarchicalDataProvider.java
new file mode 100644
index 0000000000..e43b9d6b77
--- /dev/null
+++ b/server/src/main/java/com/vaadin/data/HasHierarchicalDataProvider.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.data;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import com.vaadin.data.provider.DataProvider;
+import com.vaadin.data.provider.HierarchicalDataProvider;
+import com.vaadin.data.provider.TreeDataProvider;
+
+/**
+ * A generic interface for hierarchical listing components that use a data
+ * provider for showing data.
+ *
+ * @author Vaadin Ltd
+ * @since 8.1
+ *
+ * @param <T>
+ * the item data type
+ */
+public interface HasHierarchicalDataProvider<T> extends HasDataProvider<T> {
+
+ /**
+ * Gets the backing {@link TreeData} instance of the data provider, if the
+ * data provider is a {@link TreeDataProvider}.
+ *
+ * @return the TreeData instance used by the data provider
+ * @throws IllegalStateException
+ * if the type of the data provider is not
+ * {@link TreeDataProvider}
+ */
+ @SuppressWarnings("unchecked")
+ public default TreeData<T> getTreeData() {
+ if (getDataProvider() instanceof TreeDataProvider) {
+ return ((TreeDataProvider<T>) getDataProvider()).getTreeData();
+ } else {
+ throw new IllegalStateException("");
+ }
+ }
+
+ /**
+ * Sets the root data items of this component provided as a collection and
+ * recursively populates them with child items with the given value
+ * provider.
+ * <p>
+ * The provided items are wrapped into a {@link TreeDataProvider} backed by
+ * a flat {@link TreeData} structure. The data provider instance is used as
+ * a parameter for the {@link #setDataProvider(DataProvider)} method. It
+ * means that the items collection can be accessed later on via
+ * {@link #getTreeData()}:
+ *
+ * <pre>
+ * <code>
+ * Collection<Person> grandParents = getGrandParents();
+ * HasHierarchicalDataProvider<Person> treeGrid = new TreeGrid<>();
+ * treeGrid.setItems(grandParents, Person::getChildren);
+ * ...
+ *
+ * TreeData<Person> data = treeGrid.getTreeData();
+ * </code>
+ * </pre>
+ * <p>
+ * The returned {@link TreeData} instance may be used as-is to add, remove
+ * or modify items in the hierarchy. These modifications to the object are
+ * not automatically reflected back to the TreeGrid. Items modified should
+ * be refreshed with {@link HierarchicalDataProvider#refreshItem(Object)}
+ * and when adding or removing items
+ * {@link HierarchicalDataProvider#refreshAll()} should be called.
+ *
+ * @param rootItems
+ * the root items to display, not {@code null}
+ * @param childItemProvider
+ * the value provider used to recursively populate the given root
+ * items with child items, not {@code null}
+ */
+ public default void setItems(Collection<T> rootItems,
+ ValueProvider<T, Collection<T>> childItemProvider) {
+ Objects.requireNonNull(rootItems, "Given root items may not be null");
+ Objects.requireNonNull(childItemProvider,
+ "Given child item provider may not be null");
+ setDataProvider(new TreeDataProvider<>(
+ new TreeData<T>().addItems(rootItems, childItemProvider)));
+ }
+
+ /**
+ * Sets the data items of this component provided as a collection.
+ * <p>
+ * The provided items are wrapped into a {@link TreeDataProvider} backed by
+ * a flat {@link TreeData} structure. The data provider instance is used as
+ * a parameter for the {@link #setDataProvider(DataProvider)} method. It
+ * means that the items collection can be accessed later on via
+ * {@link #getTreeData()}:
+ *
+ * <pre>
+ * <code>
+ * HasHierarchicalDataProvider<String> treeGrid = new TreeGrid<>();
+ * treeGrid.setItems(Arrays.asList("a","b"));
+ * ...
+ *
+ * TreeData<String> data = treeGrid.getTreeData();
+ * </code>
+ * </pre>
+ * <p>
+ * The returned {@link TreeData} instance may be used as-is to add, remove
+ * or modify items in the hierarchy. These modifications to the object are
+ * not automatically reflected back to the TreeGrid. Items modified should
+ * be refreshed with {@link HierarchicalDataProvider#refreshItem(Object)}
+ * and when adding or removing items
+ * {@link HierarchicalDataProvider#refreshAll()} should be called.
+ *
+ * @param items
+ * the data items to display, not {@code null}
+ */
+ @Override
+ public default void setItems(Collection<T> items) {
+ Objects.requireNonNull(items, "Given collection may not be null");
+ setDataProvider(new TreeDataProvider<>(
+ new TreeData<T>().addItems(null, items)));
+ }
+
+ /**
+ * Sets the data items of this component provided as a stream.
+ * <p>
+ * The provided items are wrapped into a {@link TreeDataProvider} backed by
+ * a flat {@link TreeData} structure. The data provider instance is used as
+ * a parameter for the {@link #setDataProvider(DataProvider)} method. It
+ * means that the items collection can be accessed later on via
+ * {@link #getTreeData()}:
+ *
+ * <pre>
+ * <code>
+ * HasHierarchicalDataProvider<String> treeGrid = new TreeGrid<>();
+ * treeGrid.setItems(Stream.of("a","b"));
+ * ...
+ *
+ * TreeData<String> data = treeGrid.getTreeData();
+ * </code>
+ * </pre>
+ * <p>
+ * The returned {@link TreeData} instance may be used as-is to add, remove
+ * or modify items in the hierarchy. These modifications to the object are
+ * not automatically reflected back to the TreeGrid. Items modified should
+ * be refreshed with {@link HierarchicalDataProvider#refreshItem(Object)}
+ * and when adding or removing items
+ * {@link HierarchicalDataProvider#refreshAll()} should be called.
+ *
+ * @param items
+ * the data items to display, not {@code null}
+ */
+ @Override
+ public default void setItems(Stream<T> items) {
+ Objects.requireNonNull(items, "Given stream may not be null");
+ setItems(items.collect(Collectors.toList()));
+ }
+
+ /**
+ * Sets the data items of this listing.
+ * <p>
+ * The provided items are wrapped into a {@link TreeDataProvider} backed by
+ * a flat {@link TreeData} structure. The data provider instance is used as
+ * a parameter for the {@link #setDataProvider(DataProvider)} method. It
+ * means that the items collection can be accessed later on via
+ * {@link #getTreeData()}:
+ *
+ * <pre>
+ * <code>
+ * TreeGrid<String> treeGrid = new TreeGrid<>();
+ * treeGrid.setItems("a","b");
+ * ...
+ *
+ * TreeData<String> data = treeGrid.getTreeData();
+ * </code>
+ * </pre>
+ * <p>
+ * The returned {@link TreeData} instance may be used as-is to add, remove
+ * or modify items in the hierarchy. These modifications to the object are
+ * not automatically reflected back to the TreeGrid. Items modified should
+ * be refreshed with {@link HierarchicalDataProvider#refreshItem(Object)}
+ * and when adding or removing items
+ * {@link HierarchicalDataProvider#refreshAll()} should be called.
+ *
+ * @param items
+ * the data items to display, not {@code null}
+ */
+ @Override
+ public default void setItems(@SuppressWarnings("unchecked") T... items) {
+ Objects.requireNonNull(items, "Given items may not be null");
+ setItems(Arrays.asList(items));
+ }
+}
diff --git a/server/src/main/java/com/vaadin/data/HierarchyData.java b/server/src/main/java/com/vaadin/data/TreeData.java
index 0cf680db2f..def69745ef 100644
--- a/server/src/main/java/com/vaadin/data/HierarchyData.java
+++ b/server/src/main/java/com/vaadin/data/TreeData.java
@@ -34,7 +34,7 @@ import java.util.stream.Stream;
* @param <T>
* data type
*/
-public class HierarchyData<T> implements Serializable {
+public class TreeData<T> implements Serializable {
private static class HierarchyWrapper<T> implements Serializable {
private T item;
@@ -86,7 +86,7 @@ public class HierarchyData<T> implements Serializable {
* Creates an initially empty hierarchical data representation to which
* items can be added or removed.
*/
- public HierarchyData() {
+ public TreeData() {
itemToWrapperMap = new LinkedHashMap<>();
itemToWrapperMap.put(null, new HierarchyWrapper<>(null, null));
}
@@ -109,7 +109,7 @@ public class HierarchyData<T> implements Serializable {
* @throws NullPointerException
* if item is null
*/
- public HierarchyData<T> addItem(T parent, T item) {
+ public TreeData<T> addItem(T parent, T item) {
Objects.requireNonNull(item, "Item cannot be null");
if (parent != null && !contains(parent)) {
throw new IllegalArgumentException(
@@ -144,7 +144,7 @@ public class HierarchyData<T> implements Serializable {
* @throws NullPointerException
* if any of the items are null
*/
- public HierarchyData<T> addItems(T parent,
+ public TreeData<T> addItems(T parent,
@SuppressWarnings("unchecked") T... items) {
Arrays.asList(items).stream().forEach(item -> addItem(parent, item));
return this;
@@ -170,7 +170,7 @@ public class HierarchyData<T> implements Serializable {
* @throws NullPointerException
* if any of the items are null
*/
- public HierarchyData<T> addItems(T parent, Collection<T> items) {
+ public TreeData<T> addItems(T parent, Collection<T> items) {
items.stream().forEach(item -> addItem(parent, item));
return this;
}
@@ -195,12 +195,34 @@ public class HierarchyData<T> implements Serializable {
* @throws NullPointerException
* if any of the items are null
*/
- public HierarchyData<T> addItems(T parent, Stream<T> items) {
+ 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.
*
@@ -211,7 +233,7 @@ public class HierarchyData<T> implements Serializable {
* @throws IllegalArgumentException
* if the item does not exist in this structure
*/
- public HierarchyData<T> removeItem(T item) {
+ public TreeData<T> removeItem(T item) {
if (!contains(item)) {
throw new IllegalArgumentException(
"Item '" + item + "' not in the hierarchy");
@@ -232,7 +254,7 @@ public class HierarchyData<T> implements Serializable {
*
* @return this
*/
- public HierarchyData<T> clear() {
+ public TreeData<T> clear() {
removeItem(null);
return this;
}
@@ -275,4 +297,13 @@ public class HierarchyData<T> implements Serializable {
}
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);
+ });
+ }
}
diff --git a/server/src/main/java/com/vaadin/data/provider/HierarchicalDataCommunicator.java b/server/src/main/java/com/vaadin/data/provider/HierarchicalDataCommunicator.java
index 5d3bd81a05..4a8ae62772 100644
--- a/server/src/main/java/com/vaadin/data/provider/HierarchicalDataCommunicator.java
+++ b/server/src/main/java/com/vaadin/data/provider/HierarchicalDataCommunicator.java
@@ -27,7 +27,7 @@ import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import com.vaadin.data.HierarchyData;
+import com.vaadin.data.TreeData;
import com.vaadin.data.provider.HierarchyMapper.TreeLevelQuery;
import com.vaadin.data.provider.HierarchyMapper.TreeNode;
import com.vaadin.server.SerializableConsumer;
@@ -75,12 +75,12 @@ public class HierarchicalDataCommunicator<T> extends DataCommunicator<T> {
/**
* Construct a new hierarchical data communicator backed by a
- * {@link InMemoryHierarchicalDataProvider}.
+ * {@link TreeDataProvider}.
*/
public HierarchicalDataCommunicator() {
super();
- dataProvider = new InMemoryHierarchicalDataProvider<>(
- new HierarchyData<>());
+ dataProvider = new TreeDataProvider<>(
+ new TreeData<>());
}
@Override
diff --git a/server/src/main/java/com/vaadin/data/provider/InMemoryDataProvider.java b/server/src/main/java/com/vaadin/data/provider/InMemoryDataProvider.java
new file mode 100644
index 0000000000..bfb62b8dc6
--- /dev/null
+++ b/server/src/main/java/com/vaadin/data/provider/InMemoryDataProvider.java
@@ -0,0 +1,451 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.data.provider;
+
+import java.util.Locale;
+import java.util.Objects;
+
+import com.vaadin.data.ValueProvider;
+import com.vaadin.server.SerializableBiPredicate;
+import com.vaadin.server.SerializableComparator;
+import com.vaadin.server.SerializablePredicate;
+import com.vaadin.shared.data.sort.SortDirection;
+import com.vaadin.ui.UI;
+
+/**
+ * A mixin interface for in-memory data providers. Contains methods for
+ * configuring sorting and filtering.
+ *
+ * @author Vaadin Ltd
+ * @since 8.1
+ *
+ * @param <T>
+ * data type
+ */
+public interface InMemoryDataProvider<T> extends
+ ConfigurableFilterDataProvider<T, SerializablePredicate<T>, SerializablePredicate<T>> {
+
+ @Override
+ public default boolean isInMemory() {
+ return true;
+ }
+
+ /**
+ * Gets the current filter of this data provider.
+ *
+ * @return the filter of this data provider
+ */
+ public SerializablePredicate<T> getFilter();
+
+ /**
+ * Sets a filter to be applied to all queries. The filter replaces any
+ * filter that has been set or added previously.
+ *
+ * @see #setFilter(ValueProvider, SerializablePredicate)
+ * @see #setFilterByValue(ValueProvider, Object)
+ * @see #addFilter(SerializablePredicate)
+ *
+ * @param filter
+ * the filter to set, or <code>null</code> to remove any set
+ * filters
+ */
+ @Override
+ public void setFilter(SerializablePredicate<T> filter);
+
+ /**
+ * Sets a filter for an item property. The filter replaces any filter that
+ * has been set or added previously.
+ *
+ * @see #setFilter(SerializablePredicate)
+ * @see #setFilterByValue(ValueProvider, Object)
+ * @see #addFilter(ValueProvider, SerializablePredicate)
+ *
+ * @param valueProvider
+ * value provider that gets the property value, not
+ * <code>null</code>
+ * @param valueFilter
+ * filter for testing the property value, not <code>null</code>
+ */
+ public default <V> void setFilter(ValueProvider<T, V> valueProvider,
+ SerializablePredicate<V> valueFilter) {
+ setFilter(InMemoryDataProviderHelpers
+ .createValueProviderFilter(valueProvider, valueFilter));
+ }
+
+ /**
+ * Adds a filter to be applied to all queries. The filter will be used in
+ * addition to any filter that has been set or added previously.
+ *
+ * @see #addFilter(ValueProvider, SerializablePredicate)
+ * @see #addFilterByValue(ValueProvider, Object)
+ * @see #setFilter(SerializablePredicate)
+ *
+ * @param filter
+ * the filter to add, not <code>null</code>
+ */
+ public default void addFilter(SerializablePredicate<T> filter) {
+ Objects.requireNonNull(filter, "Filter cannot be null");
+
+ if (getFilter() == null) {
+ setFilter(filter);
+ } else {
+ SerializablePredicate<T> oldFilter = getFilter();
+ setFilter(item -> oldFilter.test(item) && filter.test(item));
+ }
+ }
+
+ /**
+ * Adds a filter for an item property. The filter will be used in addition
+ * to any filter that has been set or added previously.
+ *
+ * @see #addFilter(SerializablePredicate)
+ * @see #addFilterByValue(ValueProvider, Object)
+ * @see #setFilter(ValueProvider, SerializablePredicate)
+ *
+ * @param valueProvider
+ * value provider that gets the property value, not
+ * <code>null</code>
+ * @param valueFilter
+ * filter for testing the property value, not <code>null</code>
+ */
+ public default <V> void addFilter(ValueProvider<T, V> valueProvider,
+ SerializablePredicate<V> valueFilter) {
+ Objects.requireNonNull(valueProvider, "Value provider cannot be null");
+ Objects.requireNonNull(valueFilter, "Value filter cannot be null");
+
+ addFilter(InMemoryDataProviderHelpers
+ .createValueProviderFilter(valueProvider, valueFilter));
+ }
+
+ /**
+ * Sets a filter that requires an item property to have a specific value.
+ * The property value and the provided value are compared using
+ * {@link Object#equals(Object)}. The filter replaces any filter that has
+ * been set or added previously.
+ *
+ * @see #setFilter(SerializablePredicate)
+ * @see #setFilter(ValueProvider, SerializablePredicate)
+ * @see #addFilterByValue(ValueProvider, Object)
+ *
+ * @param valueProvider
+ * value provider that gets the property value, not
+ * <code>null</code>
+ * @param requiredValue
+ * the value that the property must have for the filter to pass
+ */
+ public default <V> void setFilterByValue(ValueProvider<T, V> valueProvider,
+ V requiredValue) {
+ setFilter(InMemoryDataProviderHelpers.createEqualsFilter(valueProvider,
+ requiredValue));
+ }
+
+ /**
+ * Adds a filter that requires an item property to have a specific value.
+ * The property value and the provided value are compared using
+ * {@link Object#equals(Object)}.The filter will be used in addition to any
+ * filter that has been set or added previously.
+ *
+ * @see #setFilterByValue(ValueProvider, Object)
+ * @see #addFilter(SerializablePredicate)
+ * @see #addFilter(ValueProvider, SerializablePredicate)
+ *
+ * @param valueProvider
+ * value provider that gets the property value, not
+ * <code>null</code>
+ * @param requiredValue
+ * the value that the property must have for the filter to pass
+ */
+ public default <V> void addFilterByValue(ValueProvider<T, V> valueProvider,
+ V requiredValue) {
+ addFilter(InMemoryDataProviderHelpers.createEqualsFilter(valueProvider,
+ requiredValue));
+ }
+
+ /**
+ * Removes any filter that has been set or added previously.
+ *
+ * @see #setFilter(SerializablePredicate)
+ */
+ public default void clearFilters() {
+ setFilter(null);
+ }
+
+ /**
+ * Gets the current sort comparator of this data provider.
+ *
+ * @return the sort comparator of this data provider
+ */
+ public SerializableComparator<T> getSortComparator();
+
+ /**
+ * Sets the comparator to use as the default sorting for this data provider.
+ * This overrides the sorting set by any other method that manipulates the
+ * default sorting of this data provider.
+ * <p>
+ * The default sorting is used if the query defines no sorting. The default
+ * sorting is also used to determine the ordering of items that are
+ * considered equal by the sorting defined in the query.
+ *
+ * @see #setSortOrder(ValueProvider, SortDirection)
+ * @see #addSortComparator(SerializableComparator)
+ *
+ * @param comparator
+ * a comparator to use, or <code>null</code> to clear any
+ * previously set sort order
+ */
+ public void setSortComparator(SerializableComparator<T> comparator);
+
+ /**
+ * Adds a comparator to the default sorting for this data provider. If no
+ * default sorting has been defined, then the provided comparator will be
+ * used as the default sorting. If a default sorting has been defined, then
+ * the provided comparator will be used to determine the ordering of items
+ * that are considered equal by the previously defined default sorting.
+ * <p>
+ * The default sorting is used if the query defines no sorting. The default
+ * sorting is also used to determine the ordering of items that are
+ * considered equal by the sorting defined in the query.
+ *
+ * @see #setSortComparator(SerializableComparator)
+ * @see #addSortOrder(ValueProvider, SortDirection)
+ *
+ * @param comparator
+ * a comparator to add, not <code>null</code>
+ */
+ public default void addSortComparator(
+ SerializableComparator<T> comparator) {
+ Objects.requireNonNull(comparator, "Comparator to add cannot be null");
+ SerializableComparator<T> originalComparator = getSortComparator();
+ if (originalComparator == null) {
+ setSortComparator(comparator);
+ } else {
+ setSortComparator((a, b) -> {
+ int result = originalComparator.compare(a, b);
+ if (result == 0) {
+ result = comparator.compare(a, b);
+ }
+ return result;
+ });
+ }
+ }
+
+ /**
+ * Sets the property and direction to use as the default sorting for this
+ * data provider. This overrides the sorting set by any other method that
+ * manipulates the default sorting of this data provider.
+ * <p>
+ * The default sorting is used if the query defines no sorting. The default
+ * sorting is also used to determine the ordering of items that are
+ * considered equal by the sorting defined in the query.
+ *
+ * @see #setSortComparator(SerializableComparator)
+ * @see #addSortOrder(ValueProvider, SortDirection)
+ *
+ * @param valueProvider
+ * the value provider that defines the property do sort by, not
+ * <code>null</code>
+ * @param sortDirection
+ * the sort direction to use, not <code>null</code>
+ */
+ public default <V extends Comparable<? super V>> void setSortOrder(
+ ValueProvider<T, V> valueProvider, SortDirection sortDirection) {
+ setSortComparator(InMemoryDataProviderHelpers
+ .propertyComparator(valueProvider, sortDirection));
+ }
+
+ /**
+ * Adds a property and direction to the default sorting for this data
+ * provider. If no default sorting has been defined, then the provided sort
+ * order will be used as the default sorting. If a default sorting has been
+ * defined, then the provided sort order will be used to determine the
+ * ordering of items that are considered equal by the previously defined
+ * default sorting.
+ * <p>
+ * The default sorting is used if the query defines no sorting. The default
+ * sorting is also used to determine the ordering of items that are
+ * considered equal by the sorting defined in the query.
+ *
+ * @see #setSortOrder(ValueProvider, SortDirection)
+ * @see #addSortComparator(SerializableComparator)
+ *
+ * @param valueProvider
+ * the value provider that defines the property do sort by, not
+ * <code>null</code>
+ * @param sortDirection
+ * the sort direction to use, not <code>null</code>
+ */
+ public default <V extends Comparable<? super V>> void addSortOrder(
+ ValueProvider<T, V> valueProvider, SortDirection sortDirection) {
+ addSortComparator(InMemoryDataProviderHelpers
+ .propertyComparator(valueProvider, sortDirection));
+ }
+
+ /**
+ * Wraps this data provider to create a new data provider that is filtered
+ * by comparing an item to the filter value provided in the query.
+ * <p>
+ * The predicate receives the item as the first parameter and the query
+ * filter value as the second parameter, and should return <code>true</code>
+ * if the corresponding item should be included. The query filter value is
+ * never <code>null</code> – all items are included without running the
+ * predicate if the query doesn't define any filter.
+ *
+ * @param predicate
+ * a predicate to use for comparing the item to the query filter,
+ * not <code>null</code>
+ *
+ * @return a data provider that filters accordingly, not <code>null</code>
+ */
+ public default <Q> DataProvider<T, Q> filteringBy(
+ SerializableBiPredicate<T, Q> predicate) {
+ Objects.requireNonNull(predicate, "Predicate cannot be null");
+
+ return withConvertedFilter(
+ filterValue -> item -> predicate.test(item, filterValue));
+ }
+
+ /**
+ * Wraps this data provider to create a new data provider that is filtered
+ * by comparing an item property value to the filter value provided in the
+ * query.
+ * <p>
+ * The predicate receives the property value as the first parameter and the
+ * query filter value as the second parameter, and should return
+ * <code>true</code> if the corresponding item should be included. The query
+ * filter value is never <code>null</code> – all items are included without
+ * running either callback if the query doesn't define any filter.
+ *
+ * @param valueProvider
+ * a value provider that gets the property value, not
+ * <code>null</code>
+ * @param predicate
+ * a predicate to use for comparing the property value to the
+ * query filter, not <code>null</code>
+ *
+ * @return a data provider that filters accordingly, not <code>null</code>
+ */
+ public default <V, Q> DataProvider<T, Q> filteringBy(
+ ValueProvider<T, V> valueProvider,
+ SerializableBiPredicate<V, Q> predicate) {
+ Objects.requireNonNull(valueProvider, "Value provider cannot be null");
+ Objects.requireNonNull(predicate, "Predicate cannot be null");
+
+ return filteringBy((item, filterValue) -> predicate
+ .test(valueProvider.apply(item), filterValue));
+ }
+
+ /**
+ * Wraps this data provider to create a new data provider that is filtered
+ * by testing whether the value of a property is equals to the filter value
+ * provided in the query. Equality is tested using
+ * {@link Objects#equals(Object, Object)}.
+ *
+ * @param valueProvider
+ * a value provider that gets the property value, not
+ * <code>null</code>
+ *
+ * @return a data provider that filters accordingly, not <code>null</code>
+ */
+ public default <V> DataProvider<T, V> filteringByEquals(
+ ValueProvider<T, V> valueProvider) {
+ return filteringBy(valueProvider, Objects::equals);
+ }
+
+ /**
+ * Wraps this data provider to create a new data provider that is filtered
+ * by a string by checking whether the lower case representation of the
+ * filter value provided in the query is a substring of the lower case
+ * representation of an item property value. The filter never passes if the
+ * item property value is <code>null</code>.
+ *
+ * @param valueProvider
+ * a value provider that gets the string property value, not
+ * <code>null</code>
+ * @param locale
+ * the locale to use for converting the strings to lower case,
+ * not <code>null</code>
+ * @return a data provider that filters accordingly, not <code>null</code>
+ */
+ public default DataProvider<T, String> filteringBySubstring(
+ ValueProvider<T, String> valueProvider, Locale locale) {
+ Objects.requireNonNull(locale, "Locale cannot be null");
+ return InMemoryDataProviderHelpers.filteringByCaseInsensitiveString(
+ this, valueProvider,
+ String::contains, () -> locale);
+ }
+
+ /**
+ * Wraps this data provider to create a new data provider that is filtered
+ * by a string by checking whether the lower case representation of the
+ * filter value provided in the query is a substring of the lower case
+ * representation of an item property value. Conversion to lower case is
+ * done using the locale of the {@link UI#getCurrent() current UI} if
+ * available, or otherwise {@link Locale#getDefault() the default locale}.
+ * The filter never passes if the item property value is <code>null</code>.
+ *
+ * @param valueProvider
+ * a value provider that gets the string property value, not
+ * <code>null</code>
+ * @return a data provider that filters accordingly, not <code>null</code>
+ */
+ public default DataProvider<T, String> filteringBySubstring(
+ ValueProvider<T, String> valueProvider) {
+ return InMemoryDataProviderHelpers.filteringByCaseInsensitiveString(
+ this, valueProvider, String::contains,
+ InMemoryDataProviderHelpers.CURRENT_LOCALE_SUPPLIER);
+ }
+
+ /**
+ * Wraps this data provider to create a new data provider that is filtered
+ * by a string by checking whether the lower case representation of an item
+ * property value starts with the lower case representation of the filter
+ * value provided in the query. The filter never passes if the item property
+ * value is <code>null</code>.
+ *
+ * @param valueProvider
+ * a value provider that gets the string property value, not
+ * <code>null</code>
+ * @param locale
+ * the locale to use for converting the strings to lower case,
+ * not <code>null</code>
+ * @return a data provider that filters accordingly, not <code>null</code>
+ */
+ public default DataProvider<T, String> filteringByPrefix(
+ ValueProvider<T, String> valueProvider, Locale locale) {
+ return InMemoryDataProviderHelpers.filteringByCaseInsensitiveString(this, valueProvider,
+ String::startsWith, () -> locale);
+ }
+
+ /**
+ * Wraps this data provider to create a new data provider that is filtered
+ * by a string by checking whether the lower case representation of an item
+ * property value starts with the lower case representation of the filter
+ * value provided in the query. Conversion to lower case is done using the
+ * locale of the {@link UI#getCurrent() current UI} if available, or
+ * otherwise {@link Locale#getDefault() the default locale}. The filter
+ * never passes if the item property value is <code>null</code>.
+ *
+ * @param valueProvider
+ * a value provider that gets the string property value, not
+ * <code>null</code>
+ * @return a data provider that filters accordingly, not <code>null</code>
+ */
+ public default DataProvider<T, String> filteringByPrefix(
+ ValueProvider<T, String> valueProvider) {
+ return InMemoryDataProviderHelpers.filteringByCaseInsensitiveString(this, valueProvider,
+ String::startsWith, InMemoryDataProviderHelpers.CURRENT_LOCALE_SUPPLIER);
+ }
+}
diff --git a/server/src/main/java/com/vaadin/data/provider/InMemoryDataProviderHelpers.java b/server/src/main/java/com/vaadin/data/provider/InMemoryDataProviderHelpers.java
new file mode 100644
index 0000000000..556404911c
--- /dev/null
+++ b/server/src/main/java/com/vaadin/data/provider/InMemoryDataProviderHelpers.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.data.provider;
+
+import java.util.Comparator;
+import java.util.Locale;
+import java.util.Objects;
+
+import com.vaadin.data.ValueProvider;
+import com.vaadin.server.SerializableBiPredicate;
+import com.vaadin.server.SerializableComparator;
+import com.vaadin.server.SerializablePredicate;
+import com.vaadin.server.SerializableSupplier;
+import com.vaadin.shared.data.sort.SortDirection;
+import com.vaadin.ui.UI;
+
+/**
+ * A class containing a number of static helper methods for implementing
+ * {@link InMemoryDataProvider}s.
+ * <p>
+ * This class is intended primarily for internal use.
+ *
+ * @author Vaadin Ltd
+ * @since 8.1
+ */
+public class InMemoryDataProviderHelpers {
+
+ /**
+ * Supplier that attempts to resolve a locale from the current UI. Returns
+ * the system's default locale as a fallback.
+ */
+ public static final SerializableSupplier<Locale> CURRENT_LOCALE_SUPPLIER = () -> {
+ UI currentUi = UI.getCurrent();
+ if (currentUi != null) {
+ return currentUi.getLocale();
+ } else {
+ return Locale.getDefault();
+ }
+ };
+
+ /**
+ * Wraps a given data provider so that its filter ignores null items
+ * returned by the given value provider.
+ *
+ * @param dataProvider
+ * the data provider to wrap
+ * @param valueProvider
+ * the value provider for providing values to filter
+ * @param predicate
+ * the predicate to combine null filtering with
+ * @return the wrapped data provider
+ */
+ public static <T, V, Q> DataProvider<T, Q> filteringByIgnoreNull(
+ InMemoryDataProvider<T> dataProvider,
+ ValueProvider<T, V> valueProvider,
+ SerializableBiPredicate<V, Q> predicate) {
+ Objects.requireNonNull(predicate, "Predicate cannot be null");
+
+ return dataProvider.filteringBy(valueProvider,
+ (itemValue, queryFilter) -> itemValue != null
+ && predicate.test(itemValue, queryFilter));
+ }
+
+ /**
+ * Wraps a given data provider so that its filter tests the given predicate
+ * with the lower case string provided by the given value provider.
+ *
+ * @param dataProvider
+ * the data provider to wrap
+ * @param valueProvider
+ * the value provider for providing string values to filter
+ * @param predicate
+ * the predicate to use for comparing the resulting lower case
+ * strings
+ * @param localeSupplier
+ * the locale to use when converting strings to lower case
+ * @return the wrapped data provider
+ */
+ public static <T> DataProvider<T, String> filteringByCaseInsensitiveString(
+ InMemoryDataProvider<T> dataProvider,
+ ValueProvider<T, String> valueProvider,
+ SerializableBiPredicate<String, String> predicate,
+ SerializableSupplier<Locale> localeSupplier) {
+ // Only assert since these are only passed from our own code
+ assert predicate != null;
+ assert localeSupplier != null;
+
+ return filteringByIgnoreNull(dataProvider, valueProvider,
+ (itemString, filterString) -> {
+ Locale locale = localeSupplier.get();
+ assert locale != null;
+
+ return predicate.test(itemString.toLowerCase(locale),
+ filterString.toLowerCase(locale));
+ });
+ }
+
+ /**
+ * Creates a comparator for the return type of the given
+ * {@link ValueProvider}, sorted in the direction specified by the given
+ * {@link SortDirection}.
+ *
+ * @param valueProvider
+ * the value provider to use
+ * @param sortDirection
+ * the sort direction to use
+ * @return the created comparator
+ */
+ public static <V extends Comparable<? super V>, T> SerializableComparator<T> propertyComparator(
+ ValueProvider<T, V> valueProvider, SortDirection sortDirection) {
+ Objects.requireNonNull(valueProvider, "Value provider cannot be null");
+ Objects.requireNonNull(sortDirection, "Sort direction cannot be null");
+
+ Comparator<V> comparator = getNaturalSortComparator(sortDirection);
+
+ return (a, b) -> comparator.compare(valueProvider.apply(a),
+ valueProvider.apply(b));
+ }
+
+ /**
+ * Gets the natural order comparator for the type argument, or the natural
+ * order comparator reversed if the given sorting direction is
+ * {@link SortDirection#DESCENDING}.
+ *
+ * @param sortDirection
+ * the sort direction to use
+ * @return the natural comparator, with ordering defined by the given sort
+ * direction
+ */
+ public static <V extends Comparable<? super V>> Comparator<V> getNaturalSortComparator(
+ SortDirection sortDirection) {
+ Comparator<V> comparator = Comparator.naturalOrder();
+ if (sortDirection == SortDirection.DESCENDING) {
+ comparator = comparator.reversed();
+ }
+ return comparator;
+ }
+
+ /**
+ * Creates a new predicate from the given predicate and value provider. This
+ * allows using a predicate of the value providers return type with objects
+ * of the value providers type.
+ *
+ * @param valueProvider
+ * the value provider to use
+ * @param valueFilter
+ * the original predicate
+ * @return the created predicate
+ */
+ public static <T, V> SerializablePredicate<T> createValueProviderFilter(
+ ValueProvider<T, V> valueProvider,
+ SerializablePredicate<V> valueFilter) {
+ return item -> valueFilter.test(valueProvider.apply(item));
+ }
+
+ /**
+ * Creates a predicate that compares equality of the given required value to
+ * the value the given value provider obtains.
+ *
+ * @param valueProvider
+ * the value provider to use
+ * @param requiredValue
+ * the required value
+ * @return the created predicate
+ */
+ public static <T, V> SerializablePredicate<T> createEqualsFilter(
+ ValueProvider<T, V> valueProvider, V requiredValue) {
+ Objects.requireNonNull(valueProvider, "Value provider cannot be null");
+
+ return item -> Objects.equals(valueProvider.apply(item), requiredValue);
+ }
+}
diff --git a/server/src/main/java/com/vaadin/data/provider/ListDataProvider.java b/server/src/main/java/com/vaadin/data/provider/ListDataProvider.java
index fba2f94d9d..eef0b0388e 100644
--- a/server/src/main/java/com/vaadin/data/provider/ListDataProvider.java
+++ b/server/src/main/java/com/vaadin/data/provider/ListDataProvider.java
@@ -17,18 +17,12 @@ package com.vaadin.data.provider;
import java.util.Collection;
import java.util.Comparator;
-import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
-import com.vaadin.data.ValueProvider;
-import com.vaadin.server.SerializableBiPredicate;
import com.vaadin.server.SerializableComparator;
import com.vaadin.server.SerializablePredicate;
-import com.vaadin.server.SerializableSupplier;
-import com.vaadin.shared.data.sort.SortDirection;
-import com.vaadin.ui.UI;
/**
* {@link DataProvider} wrapper for {@link Collection}s.
@@ -38,17 +32,8 @@ import com.vaadin.ui.UI;
* @since 8.0
*/
public class ListDataProvider<T>
- extends AbstractDataProvider<T, SerializablePredicate<T>> implements
- ConfigurableFilterDataProvider<T, SerializablePredicate<T>, SerializablePredicate<T>> {
-
- private static final SerializableSupplier<Locale> CURRENT_LOCALE_SUPPLIER = () -> {
- UI currentUi = UI.getCurrent();
- if (currentUi != null) {
- return currentUi.getLocale();
- } else {
- return Locale.getDefault();
- }
- };
+ extends AbstractDataProvider<T, SerializablePredicate<T>>
+ implements InMemoryDataProvider<T> {
private SerializableComparator<T> sortOrder = null;
@@ -98,11 +83,6 @@ public class ListDataProvider<T>
}
@Override
- public boolean isInMemory() {
- return true;
- }
-
- @Override
public int size(Query<T, SerializablePredicate<T>> query) {
return (int) getFilteredStream(query).count();
}
@@ -122,454 +102,25 @@ public class ListDataProvider<T>
return stream;
}
- /**
- * Sets the comparator to use as the default sorting for this data provider.
- * This overrides the sorting set by any other method that manipulates the
- * default sorting of this data provider.
- * <p>
- * The default sorting is used if the query defines no sorting. The default
- * sorting is also used to determine the ordering of items that are
- * considered equal by the sorting defined in the query.
- *
- * @see #setSortOrder(ValueProvider, SortDirection)
- * @see #addSortComparator(SerializableComparator)
- *
- * @param comparator
- * a comparator to use, or <code>null</code> to clear any
- * previously set sort order
- */
+ @Override
+ public SerializableComparator<T> getSortComparator() {
+ return sortOrder;
+ }
+
+ @Override
public void setSortComparator(SerializableComparator<T> comparator) {
this.sortOrder = comparator;
refreshAll();
}
- /**
- * Sets the property and direction to use as the default sorting for this
- * data provider. This overrides the sorting set by any other method that
- * manipulates the default sorting of this data provider.
- * <p>
- * The default sorting is used if the query defines no sorting. The default
- * sorting is also used to determine the ordering of items that are
- * considered equal by the sorting defined in the query.
- *
- * @see #setSortComparator(SerializableComparator)
- * @see #addSortOrder(ValueProvider, SortDirection)
- *
- * @param valueProvider
- * the value provider that defines the property do sort by, not
- * <code>null</code>
- * @param sortDirection
- * the sort direction to use, not <code>null</code>
- */
- public <V extends Comparable<? super V>> void setSortOrder(
- ValueProvider<T, V> valueProvider, SortDirection sortDirection) {
- setSortComparator(propertyComparator(valueProvider, sortDirection));
- }
-
- /**
- * Adds a comparator to the default sorting for this data provider. If no
- * default sorting has been defined, then the provided comparator will be
- * used as the default sorting. If a default sorting has been defined, then
- * the provided comparator will be used to determine the ordering of items
- * that are considered equal by the previously defined default sorting.
- * <p>
- * The default sorting is used if the query defines no sorting. The default
- * sorting is also used to determine the ordering of items that are
- * considered equal by the sorting defined in the query.
- *
- * @see #setSortComparator(SerializableComparator)
- * @see #addSortOrder(ValueProvider, SortDirection)
- *
- * @param comparator
- * a comparator to add, not <code>null</code>
- */
- public void addSortComparator(SerializableComparator<T> comparator) {
- Objects.requireNonNull(comparator, "Sort order to add cannot be null");
-
- SerializableComparator<T> originalComparator = this.sortOrder;
- if (originalComparator == null) {
- setSortComparator(comparator);
- } else {
- setSortComparator((a, b) -> {
- int result = originalComparator.compare(a, b);
- if (result == 0) {
- result = comparator.compare(a, b);
- }
- return result;
- });
- }
- }
-
- /**
- * Adds a property and direction to the default sorting for this data
- * provider. If no default sorting has been defined, then the provided sort
- * order will be used as the default sorting. If a default sorting has been
- * defined, then the provided sort order will be used to determine the
- * ordering of items that are considered equal by the previously defined
- * default sorting.
- * <p>
- * The default sorting is used if the query defines no sorting. The default
- * sorting is also used to determine the ordering of items that are
- * considered equal by the sorting defined in the query.
- *
- * @see #setSortOrder(ValueProvider, SortDirection)
- * @see #addSortComparator(SerializableComparator)
- *
- * @param valueProvider
- * the value provider that defines the property do sort by, not
- * <code>null</code>
- * @param sortDirection
- * the sort direction to use, not <code>null</code>
- */
- public <V extends Comparable<? super V>> void addSortOrder(
- ValueProvider<T, V> valueProvider, SortDirection sortDirection) {
- addSortComparator(propertyComparator(valueProvider, sortDirection));
- }
-
- private static <V extends Comparable<? super V>, T> SerializableComparator<T> propertyComparator(
- ValueProvider<T, V> valueProvider, SortDirection sortDirection) {
- Objects.requireNonNull(valueProvider, "Value provider cannot be null");
- Objects.requireNonNull(sortDirection, "Sort direction cannot be null");
-
- Comparator<V> comparator = getNaturalSortComparator(sortDirection);
-
- return (a, b) -> comparator.compare(valueProvider.apply(a),
- valueProvider.apply(b));
- }
-
- private static <V extends Comparable<? super V>> Comparator<V> getNaturalSortComparator(
- SortDirection sortDirection) {
- Comparator<V> comparator = Comparator.naturalOrder();
- if (sortDirection == SortDirection.DESCENDING) {
- comparator = comparator.reversed();
- }
- return comparator;
+ @Override
+ public SerializablePredicate<T> getFilter() {
+ return filter;
}
- /**
- * Sets a filter to be applied to all queries. The filter replaces any
- * filter that has been set or added previously.
- *
- * @see #setFilter(ValueProvider, SerializablePredicate)
- * @see #setFilterByValue(ValueProvider, Object)
- * @see #addFilter(SerializablePredicate)
- *
- * @param filter
- * the filter to set, or <code>null</code> to remove any set
- * filters
- */
@Override
public void setFilter(SerializablePredicate<T> filter) {
this.filter = filter;
refreshAll();
}
-
- /**
- * Adds a filter to be applied to all queries. The filter will be used in
- * addition to any filter that has been set or added previously.
- *
- * @see #addFilter(ValueProvider, SerializablePredicate)
- * @see #addFilterByValue(ValueProvider, Object)
- * @see #setFilter(SerializablePredicate)
- *
- * @param filter
- * the filter to add, not <code>null</code>
- */
- public void addFilter(SerializablePredicate<T> filter) {
- Objects.requireNonNull(filter, "Filter cannot be null");
-
- if (this.filter == null) {
- setFilter(filter);
- } else {
- SerializablePredicate<T> oldFilter = this.filter;
- setFilter(item -> oldFilter.test(item) && filter.test(item));
- }
- }
-
- /**
- * Removes any filter that has been set or added previously.
- *
- * @see #setFilter(SerializablePredicate)
- */
- public void clearFilters() {
- setFilter(null);
- }
-
- /**
- * Sets a filter for an item property. The filter replaces any filter that
- * has been set or added previously.
- *
- * @see #setFilter(SerializablePredicate)
- * @see #setFilterByValue(ValueProvider, Object)
- * @see #addFilter(ValueProvider, SerializablePredicate)
- *
- * @param valueProvider
- * value provider that gets the property value, not
- * <code>null</code>
- * @param valueFilter
- * filter for testing the property value, not <code>null</code>
- */
- public <V> void setFilter(ValueProvider<T, V> valueProvider,
- SerializablePredicate<V> valueFilter) {
- setFilter(createValueProviderFilter(valueProvider, valueFilter));
- }
-
- /**
- * Adds a filter for an item property. The filter will be used in addition
- * to any filter that has been set or added previously.
- *
- * @see #addFilter(SerializablePredicate)
- * @see #addFilterByValue(ValueProvider, Object)
- * @see #setFilter(ValueProvider, SerializablePredicate)
- *
- * @param valueProvider
- * value provider that gets the property value, not
- * <code>null</code>
- * @param valueFilter
- * filter for testing the property value, not <code>null</code>
- */
- public <V> void addFilter(ValueProvider<T, V> valueProvider,
- SerializablePredicate<V> valueFilter) {
- Objects.requireNonNull(valueProvider, "Value provider cannot be null");
- Objects.requireNonNull(valueFilter, "Value filter cannot be null");
-
- addFilter(createValueProviderFilter(valueProvider, valueFilter));
- }
-
- private static <T, V> SerializablePredicate<T> createValueProviderFilter(
- ValueProvider<T, V> valueProvider,
- SerializablePredicate<V> valueFilter) {
- return item -> valueFilter.test(valueProvider.apply(item));
- }
-
- /**
- * Sets a filter that requires an item property to have a specific value.
- * The property value and the provided value are compared using
- * {@link Object#equals(Object)}. The filter replaces any filter that has
- * been set or added previously.
- *
- * @see #setFilter(SerializablePredicate)
- * @see #setFilter(ValueProvider, SerializablePredicate)
- * @see #addFilterByValue(ValueProvider, Object)
- *
- * @param valueProvider
- * value provider that gets the property value, not
- * <code>null</code>
- * @param requiredValue
- * the value that the property must have for the filter to pass
- */
- public <V> void setFilterByValue(ValueProvider<T, V> valueProvider,
- V requiredValue) {
- setFilter(createEqualsFilter(valueProvider, requiredValue));
- }
-
- /**
- * Adds a filter that requires an item property to have a specific value.
- * The property value and the provided value are compared using
- * {@link Object#equals(Object)}.The filter will be used in addition to any
- * filter that has been set or added previously.
- *
- * @see #setFilterByValue(ValueProvider, Object)
- * @see #addFilter(SerializablePredicate)
- * @see #addFilter(ValueProvider, SerializablePredicate)
- *
- * @param valueProvider
- * value provider that gets the property value, not
- * <code>null</code>
- * @param requiredValue
- * the value that the property must have for the filter to pass
- */
- public <V> void addFilterByValue(ValueProvider<T, V> valueProvider,
- V requiredValue) {
- addFilter(createEqualsFilter(valueProvider, requiredValue));
- }
-
- private static <T, V> SerializablePredicate<T> createEqualsFilter(
- ValueProvider<T, V> valueProvider, V requiredValue) {
- Objects.requireNonNull(valueProvider, "Value provider cannot be null");
-
- return item -> Objects.equals(valueProvider.apply(item), requiredValue);
- }
-
- /**
- * Wraps this data provider to create a new data provider that is filtered
- * by comparing an item to the filter value provided in the query.
- * <p>
- * The predicate receives the item as the first parameter and the query
- * filter value as the second parameter, and should return <code>true</code>
- * if the corresponding item should be included. The query filter value is
- * never <code>null</code> – all items are included without running the
- * predicate if the query doesn't define any filter.
- *
- * @param predicate
- * a predicate to use for comparing the item to the query filter,
- * not <code>null</code>
- *
- * @return a data provider that filters accordingly, not <code>null</code>
- */
- public <Q> DataProvider<T, Q> filteringBy(
- SerializableBiPredicate<T, Q> predicate) {
- Objects.requireNonNull(predicate, "Predicate cannot be null");
-
- return withConvertedFilter(
- filterValue -> item -> predicate.test(item, filterValue));
- }
-
- /**
- * Wraps this data provider to create a new data provider that is filtered
- * by comparing an item property value to the filter value provided in the
- * query.
- * <p>
- * The predicate receives the property value as the first parameter and the
- * query filter value as the second parameter, and should return
- * <code>true</code> if the corresponding item should be included. The query
- * filter value is never <code>null</code> – all items are included without
- * running either callback if the query doesn't define any filter.
- *
- * @param valueProvider
- * a value provider that gets the property value, not
- * <code>null</code>
- * @param predicate
- * a predicate to use for comparing the property value to the
- * query filter, not <code>null</code>
- *
- * @return a data provider that filters accordingly, not <code>null</code>
- */
- public <V, Q> DataProvider<T, Q> filteringBy(
- ValueProvider<T, V> valueProvider,
- SerializableBiPredicate<V, Q> predicate) {
- Objects.requireNonNull(valueProvider, "Value provider cannot be null");
- Objects.requireNonNull(predicate, "Predicate cannot be null");
-
- return filteringBy((item, filterValue) -> predicate
- .test(valueProvider.apply(item), filterValue));
- }
-
- /**
- * Wraps this data provider to create a new data provider that is filtered
- * by testing whether the value of a property is equals to the filter value
- * provided in the query. Equality is tested using
- * {@link Objects#equals(Object, Object)}.
- *
- * @param valueProvider
- * a value provider that gets the property value, not
- * <code>null</code>
- *
- * @return a data provider that filters accordingly, not <code>null</code>
- */
- public <V> DataProvider<T, V> filteringByEquals(
- ValueProvider<T, V> valueProvider) {
- return filteringBy(valueProvider, Objects::equals);
- }
-
- private <V, Q> DataProvider<T, Q> filteringByIgnoreNull(
- ValueProvider<T, V> valueProvider,
- SerializableBiPredicate<V, Q> predicate) {
- Objects.requireNonNull(predicate, "Predicate cannot be null");
-
- return filteringBy(valueProvider,
- (itemValue, queryFilter) -> itemValue != null
- && predicate.test(itemValue, queryFilter));
- }
-
- /**
- * Wraps this data provider to create a new data provider that is filtered
- * by a string by checking whether the lower case representation of the
- * filter value provided in the query is a substring of the lower case
- * representation of an item property value. The filter never passes if the
- * item property value is <code>null</code>.
- *
- * @param valueProvider
- * a value provider that gets the string property value, not
- * <code>null</code>
- * @param locale
- * the locale to use for converting the strings to lower case,
- * not <code>null</code>
- * @return a data provider that filters accordingly, not <code>null</code>
- */
- public DataProvider<T, String> filteringBySubstring(
- ValueProvider<T, String> valueProvider, Locale locale) {
- Objects.requireNonNull(locale, "Locale cannot be null");
- return filteringByCaseInsensitiveString(valueProvider, String::contains,
- () -> locale);
- }
-
- /**
- * Wraps this data provider to create a new data provider that is filtered
- * by a string by checking whether the lower case representation of the
- * filter value provided in the query is a substring of the lower case
- * representation of an item property value. Conversion to lower case is
- * done using the locale of the {@link UI#getCurrent() current UI} if
- * available, or otherwise {@link Locale#getDefault() the default locale}.
- * The filter never passes if the item property value is <code>null</code>.
- *
- * @param valueProvider
- * a value provider that gets the string property value, not
- * <code>null</code>
- * @return a data provider that filters accordingly, not <code>null</code>
- */
- public DataProvider<T, String> filteringBySubstring(
- ValueProvider<T, String> valueProvider) {
- return filteringByCaseInsensitiveString(valueProvider, String::contains,
- CURRENT_LOCALE_SUPPLIER);
- }
-
- /**
- * Wraps this data provider to create a new data provider that is filtered
- * by a string by checking whether the lower case representation of an item
- * property value starts with the lower case representation of the filter
- * value provided in the query. The filter never passes if the item property
- * value is <code>null</code>.
- *
- * @param valueProvider
- * a value provider that gets the string property value, not
- * <code>null</code>
- * @param locale
- * the locale to use for converting the strings to lower case,
- * not <code>null</code>
- * @return a data provider that filters accordingly, not <code>null</code>
- */
- public DataProvider<T, String> filteringByPrefix(
- ValueProvider<T, String> valueProvider, Locale locale) {
- return filteringByCaseInsensitiveString(valueProvider,
- String::startsWith, () -> locale);
- }
-
- /**
- * Wraps this data provider to create a new data provider that is filtered
- * by a string by checking whether the lower case representation of an item
- * property value starts with the lower case representation of the filter
- * value provided in the query. Conversion to lower case is done using the
- * locale of the {@link UI#getCurrent() current UI} if available, or
- * otherwise {@link Locale#getDefault() the default locale}. The filter
- * never passes if the item property value is <code>null</code>.
- *
- * @param valueProvider
- * a value provider that gets the string property value, not
- * <code>null</code>
- * @return a data provider that filters accordingly, not <code>null</code>
- */
- public DataProvider<T, String> filteringByPrefix(
- ValueProvider<T, String> valueProvider) {
- return filteringByCaseInsensitiveString(valueProvider,
- String::startsWith, CURRENT_LOCALE_SUPPLIER);
- }
-
- private DataProvider<T, String> filteringByCaseInsensitiveString(
- ValueProvider<T, String> valueProvider,
- SerializableBiPredicate<String, String> predicate,
- SerializableSupplier<Locale> localeSupplier) {
- // Only assert since these are only passed from our own code
- assert predicate != null;
- assert localeSupplier != null;
-
- return filteringByIgnoreNull(valueProvider,
- (itemString, filterString) -> {
- Locale locale = localeSupplier.get();
- assert locale != null;
-
- return predicate.test(itemString.toLowerCase(locale),
- filterString.toLowerCase(locale));
- });
- }
}
diff --git a/server/src/main/java/com/vaadin/data/provider/InMemoryHierarchicalDataProvider.java b/server/src/main/java/com/vaadin/data/provider/TreeDataProvider.java
index 8f70dd8e8c..b30a286afa 100644
--- a/server/src/main/java/com/vaadin/data/provider/InMemoryHierarchicalDataProvider.java
+++ b/server/src/main/java/com/vaadin/data/provider/TreeDataProvider.java
@@ -20,17 +20,13 @@ 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.data.TreeData;
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
+ * {@link HierarchicalDataProvider} wrapper for {@link TreeData}.
*
* @author Vaadin Ltd
* @since 8.1
@@ -38,27 +34,27 @@ import com.vaadin.shared.data.sort.SortDirection;
* @param <T>
* data type
*/
-public class InMemoryHierarchicalDataProvider<T> extends
- AbstractHierarchicalDataProvider<T, SerializablePredicate<T>> implements
- ConfigurableFilterDataProvider<T, SerializablePredicate<T>, SerializablePredicate<T>> {
+public class TreeDataProvider<T>
+ extends AbstractHierarchicalDataProvider<T, SerializablePredicate<T>>
+ implements InMemoryDataProvider<T> {
- private final HierarchyData<T> hierarchyData;
+ private final TreeData<T> treeData;
private SerializablePredicate<T> filter = null;
private SerializableComparator<T> sortOrder = null;
/**
- * Constructs a new InMemoryHierarchicalDataProvider.
+ * Constructs a new TreeDataProvider.
* <p>
- * All changes made to the given HierarchyData object will also be visible
- * through this data provider.
+ * All changes made to the given {@link TreeData} object will also be
+ * visible through this data provider.
*
- * @param hierarchyData
- * the backing HierarchyData for this provider
+ * @param treeData
+ * the backing {@link TreeData} for this provider
*/
- public InMemoryHierarchicalDataProvider(HierarchyData<T> hierarchyData) {
- this.hierarchyData = hierarchyData;
+ public TreeDataProvider(TreeData<T> treeData) {
+ this.treeData = treeData;
}
/**
@@ -66,24 +62,19 @@ public class InMemoryHierarchicalDataProvider<T> extends
*
* @return the underlying data of this provider
*/
- public HierarchyData<T> getData() {
- return hierarchyData;
- }
-
- @Override
- public boolean isInMemory() {
- return true;
+ public TreeData<T> getTreeData() {
+ return treeData;
}
@Override
public boolean hasChildren(T item) {
- if (!hierarchyData.contains(item)) {
+ if (!treeData.contains(item)) {
throw new IllegalArgumentException("Item " + item
- + " could not be found in the backing HierarchyData. "
+ + " could not be found in the backing TreeData. "
+ "Did you forget to refresh this data provider after item removal?");
}
- return !hierarchyData.getChildren(item).isEmpty();
+ return !treeData.getChildren(item).isEmpty();
}
@Override
@@ -95,15 +86,15 @@ public class InMemoryHierarchicalDataProvider<T> extends
@Override
public Stream<T> fetchChildren(
HierarchicalQuery<T, SerializablePredicate<T>> query) {
- if (!hierarchyData.contains(query.getParent())) {
+ if (!treeData.contains(query.getParent())) {
throw new IllegalArgumentException("The queried item "
+ query.getParent()
- + " could not be found in the backing HierarchyData. "
+ + " could not be found in the backing TreeData. "
+ "Did you forget to refresh this data provider after item removal?");
}
Stream<T> childStream = getFilteredStream(
- hierarchyData.getChildren(query.getParent()).stream(),
+ treeData.getChildren(query.getParent()).stream(),
query.getFilter());
Optional<Comparator<T>> comparing = Stream
@@ -119,87 +110,27 @@ public class InMemoryHierarchicalDataProvider<T> extends
}
@Override
+ public SerializablePredicate<T> getFilter() {
+ return filter;
+ }
+
+ @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));
- }
+ @Override
+ public SerializableComparator<T> getSortComparator() {
+ return sortOrder;
}
- /**
- * 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 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) {
diff --git a/server/src/main/java/com/vaadin/ui/Tree.java b/server/src/main/java/com/vaadin/ui/Tree.java
index 97e1b94cec..9a765238c1 100644
--- a/server/src/main/java/com/vaadin/ui/Tree.java
+++ b/server/src/main/java/com/vaadin/ui/Tree.java
@@ -24,7 +24,7 @@ import java.util.Objects;
import java.util.Set;
import com.vaadin.data.Binder;
-import com.vaadin.data.HasDataProvider;
+import com.vaadin.data.HasHierarchicalDataProvider;
import com.vaadin.data.SelectionModel;
import com.vaadin.data.provider.DataGenerator;
import com.vaadin.data.provider.DataProvider;
@@ -57,7 +57,8 @@ import elemental.json.JsonObject;
* @param <T>
* the data type
*/
-public class Tree<T> extends Composite implements HasDataProvider<T> {
+public class Tree<T> extends Composite
+ implements HasHierarchicalDataProvider<T> {
@Deprecated
private static final Method ITEM_CLICK_METHOD = ReflectTools
@@ -422,11 +423,6 @@ public class Tree<T> extends Composite implements HasDataProvider<T> {
return treeGrid.getSelectionModel();
}
- @Override
- public void setItems(Collection<T> items) {
- treeGrid.setItems(items);
- }
-
/**
* Sets the item caption generator that is used to produce the strings shown
* as the text for each item. By default, {@link String#valueOf(Object)} is
diff --git a/server/src/main/java/com/vaadin/ui/TreeGrid.java b/server/src/main/java/com/vaadin/ui/TreeGrid.java
index 720bffaf3e..1b051d1da6 100644
--- a/server/src/main/java/com/vaadin/ui/TreeGrid.java
+++ b/server/src/main/java/com/vaadin/ui/TreeGrid.java
@@ -21,19 +21,19 @@ import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
-import java.util.stream.Stream;
import org.jsoup.nodes.Attributes;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
-import com.vaadin.data.HierarchyData;
+import com.vaadin.data.HasHierarchicalDataProvider;
+import com.vaadin.data.TreeData;
import com.vaadin.data.ValueProvider;
import com.vaadin.data.provider.DataProvider;
import com.vaadin.data.provider.HierarchicalDataCommunicator;
import com.vaadin.data.provider.HierarchicalDataProvider;
import com.vaadin.data.provider.HierarchicalQuery;
-import com.vaadin.data.provider.InMemoryHierarchicalDataProvider;
+import com.vaadin.data.provider.TreeDataProvider;
import com.vaadin.event.CollapseEvent;
import com.vaadin.event.CollapseEvent.CollapseListener;
import com.vaadin.event.ExpandEvent;
@@ -60,7 +60,8 @@ import com.vaadin.ui.renderers.Renderer;
* @param <T>
* the grid bean type
*/
-public class TreeGrid<T> extends Grid<T> {
+public class TreeGrid<T> extends Grid<T>
+ implements HasHierarchicalDataProvider<T> {
public TreeGrid() {
super(new HierarchicalDataCommunicator<>());
@@ -125,117 +126,6 @@ public class TreeGrid<T> extends Grid<T> {
CollapseListener.COLLAPSE_METHOD);
}
- /**
- * Sets the data items of this component provided as a collection.
- * <p>
- * The provided items are wrapped into a
- * {@link InMemoryHierarchicalDataProvider} backed by a flat
- * {@link HierarchyData} structure. The data provider instance is used as a
- * parameter for the {@link #setDataProvider(DataProvider)} method. It means
- * that the items collection can be accessed later on via
- * {@link InMemoryHierarchicalDataProvider#getData()}:
- *
- * <pre>
- * <code>
- * TreeGrid<String> treeGrid = new TreeGrid<>();
- * treeGrid.setItems(Arrays.asList("a","b"));
- * ...
- *
- * HierarchyData<String> data = ((InMemoryHierarchicalDataProvider<String>)treeGrid.getDataProvider()).getData();
- * </code>
- * </pre>
- * <p>
- * The returned HierarchyData instance may be used as-is to add, remove or
- * modify items in the hierarchy. These modifications to the object are not
- * automatically reflected back to the TreeGrid. Items modified should be
- * refreshed with {@link HierarchicalDataProvider#refreshItem(Object)} and
- * when adding or removing items
- * {@link HierarchicalDataProvider#refreshAll()} should be called.
- *
- * @param items
- * the data items to display, not null
- */
- @Override
- public void setItems(Collection<T> items) {
- Objects.requireNonNull(items, "Given collection may not be null");
- setDataProvider(new InMemoryHierarchicalDataProvider<>(
- new HierarchyData<T>().addItems(null, items)));
- }
-
- /**
- * Sets the data items of this component provided as a stream.
- * <p>
- * The provided items are wrapped into a
- * {@link InMemoryHierarchicalDataProvider} backed by a flat
- * {@link HierarchyData} structure. The data provider instance is used as a
- * parameter for the {@link #setDataProvider(DataProvider)} method. It means
- * that the items collection can be accessed later on via
- * {@link InMemoryHierarchicalDataProvider#getData()}:
- *
- * <pre>
- * <code>
- * TreeGrid<String> treeGrid = new TreeGrid<>();
- * treeGrid.setItems(Stream.of("a","b"));
- * ...
- *
- * HierarchyData<String> data = ((InMemoryHierarchicalDataProvider<String>)treeGrid.getDataProvider()).getData();
- * </code>
- * </pre>
- * <p>
- * The returned HierarchyData instance may be used as-is to add, remove or
- * modify items in the hierarchy. These modifications to the object are not
- * automatically reflected back to the TreeGrid. Items modified should be
- * refreshed with {@link HierarchicalDataProvider#refreshItem(Object)} and
- * when adding or removing items
- * {@link HierarchicalDataProvider#refreshAll()} should be called.
- *
- * @param items
- * the data items to display, not null
- */
- @Override
- public void setItems(Stream<T> items) {
- Objects.requireNonNull(items, "Given stream may not be null");
- setDataProvider(new InMemoryHierarchicalDataProvider<>(
- new HierarchyData<T>().addItems(null, items)));
- }
-
- /**
- * Sets the data items of this listing.
- * <p>
- * The provided items are wrapped into a
- * {@link InMemoryHierarchicalDataProvider} backed by a flat
- * {@link HierarchyData} structure. The data provider instance is used as a
- * parameter for the {@link #setDataProvider(DataProvider)} method. It means
- * that the items collection can be accessed later on via
- * {@link InMemoryHierarchicalDataProvider#getData()}:
- *
- * <pre>
- * <code>
- * TreeGrid<String> treeGrid = new TreeGrid<>();
- * treeGrid.setItems("a","b");
- * ...
- *
- * HierarchyData<String> data = ((InMemoryHierarchicalDataProvider<String>)treeGrid.getDataProvider()).getData();
- * </code>
- * </pre>
- * <p>
- * The returned HierarchyData instance may be used as-is to add, remove or
- * modify items in the hierarchy. These modifications to the object are not
- * automatically reflected back to the TreeGrid. Items modified should be
- * refreshed with {@link HierarchicalDataProvider#refreshItem(Object)} and
- * when adding or removing items
- * {@link HierarchicalDataProvider#refreshAll()} should be called.
- *
- * @param items
- * the data items to display, not null
- */
- @Override
- public void setItems(@SuppressWarnings("unchecked") T... items) {
- Objects.requireNonNull(items, "Given items may not be null");
- setDataProvider(new InMemoryHierarchicalDataProvider<>(
- new HierarchyData<T>().addItems(null, items)));
- }
-
@Override
public void setDataProvider(DataProvider<T, ?> dataProvider) {
if (!(dataProvider instanceof HierarchicalDataProvider)) {
@@ -395,7 +285,7 @@ public class TreeGrid<T> extends Grid<T> {
List<DeclarativeValueProvider<T>> providers) {
getSelectionModel().deselectAll();
List<T> selectedItems = new ArrayList<>();
- HierarchyData<T> data = new HierarchyData<T>();
+ TreeData<T> data = new TreeData<T>();
for (Element row : body.children()) {
T item = deserializeDeclarativeRepresentation(row.attr("item"));
@@ -416,7 +306,7 @@ public class TreeGrid<T> extends Grid<T> {
}
}
- setDataProvider(new InMemoryHierarchicalDataProvider<>(data));
+ setDataProvider(new TreeDataProvider<>(data));
selectedItems.forEach(getSelectionModel()::select);
}