From 5447e7e05392483455f7df4bf2af5d5d74e5a2ae Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Sun, 22 Jan 2017 21:50:46 +0200 Subject: Add ListDataProvider shorthands for filter conversion (#8279) Also updates ComboBox.setItems to use these new shorthands This is one of many steps towards #8245 --- .../com/vaadin/data/provider/ListDataProvider.java | 195 +++++++++++++++++++++ 1 file changed, 195 insertions(+) (limited to 'server/src/main/java/com/vaadin/data') 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 470339bc2a..4269ddbeff 100644 --- a/server/src/main/java/com/vaadin/data/provider/ListDataProvider.java +++ b/server/src/main/java/com/vaadin/data/provider/ListDataProvider.java @@ -17,14 +17,18 @@ 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. This class does not @@ -38,6 +42,15 @@ public class ListDataProvider implements AppendableFilterDataProvider>, ConfigurableFilterDataProvider, SerializablePredicate> { + private static final SerializableSupplier CURRENT_LOCALE_SUPPLIER = () -> { + UI currentUi = UI.getCurrent(); + if (currentUi != null) { + return currentUi.getLocale(); + } else { + return Locale.getDefault(); + } + }; + private SerializableComparator sortOrder = null; private SerializablePredicate filter; @@ -376,4 +389,186 @@ public class ListDataProvider SerializablePredicate filter2) { return t -> filter1.test(t) && filter2.test(t); } + + /** + * 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. + *

+ * The predicate receives the item as the first parameter and the query + * filter value as the second parameter, and should return true + * if the corresponding item should be included. The query filter value is + * never null – 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 null + * + * @return a data provider that filters accordingly, not null + */ + public DataProvider filteringBy( + SerializableBiPredicate predicate) { + Objects.requireNonNull(predicate, "Predicate cannot be null"); + + return convertFilter( + 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. + *

+ * The predicate receives the property value as the first parameter and the + * query filter value as the second parameter, and should return + * true if the corresponding item should be included. The query + * filter value is never null – 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 + * null + * @param predicate + * a predicate to use for comparing the property value to the + * query filter, not null + * + * @return a data provider that filters accordingly, not null + */ + public DataProvider filteringBy( + ValueProvider valueProvider, + SerializableBiPredicate 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 + * null + * + * @return a data provider that filters accordingly, not null + */ + public DataProvider filteringByEquals( + ValueProvider valueProvider) { + return filteringBy(valueProvider, Objects::equals); + } + + private DataProvider filteringByIgnoreNull( + ValueProvider valueProvider, + SerializableBiPredicate 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 null. + * + * @param valueProvider + * a value provider that gets the string property value, not + * null + * @param locale + * the locale to use for converting the strings to lower case, + * not null + * @return a data provider that filters accordingly, not null + */ + public DataProvider filteringBySubstring( + ValueProvider 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 null. + * + * @param valueProvider + * a value provider that gets the string property value, not + * null + * @return a data provider that filters accordingly, not null + */ + public DataProvider filteringBySubstring( + ValueProvider 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 null. + * + * @param valueProvider + * a value provider that gets the string property value, not + * null + * @param locale + * the locale to use for converting the strings to lower case, + * not null + * @return a data provider that filters accordingly, not null + */ + public DataProvider filteringByPrefix( + ValueProvider 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 null. + * + * @param valueProvider + * a value provider that gets the string property value, not + * null + * @return a data provider that filters accordingly, not null + */ + public DataProvider filteringByPrefix( + ValueProvider valueProvider) { + return filteringByCaseInsensitiveString(valueProvider, + String::startsWith, CURRENT_LOCALE_SUPPLIER); + } + + private DataProvider filteringByCaseInsensitiveString( + ValueProvider valueProvider, + SerializableBiPredicate predicate, + SerializableSupplier 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)); + }); + } } -- cgit v1.2.3