diff options
author | Leif Åstrand <legioth@gmail.com> | 2017-01-22 21:50:46 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-01-22 21:50:46 +0200 |
commit | 5447e7e05392483455f7df4bf2af5d5d74e5a2ae (patch) | |
tree | 5028592fea2d9f1dda0c23d1448b92b8a35dc6fd /server/src/main/java/com/vaadin/data | |
parent | 19427ba7c7a51d3af61c170a7ba54137eb629ac8 (diff) | |
download | vaadin-framework-5447e7e05392483455f7df4bf2af5d5d74e5a2ae.tar.gz vaadin-framework-5447e7e05392483455f7df4bf2af5d5d74e5a2ae.zip |
Add ListDataProvider shorthands for filter conversion (#8279)
Also updates ComboBox.setItems to use these new shorthands
This is one of many steps towards #8245
Diffstat (limited to 'server/src/main/java/com/vaadin/data')
-rw-r--r-- | server/src/main/java/com/vaadin/data/provider/ListDataProvider.java | 195 |
1 files changed, 195 insertions, 0 deletions
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<T> implements AppendableFilterDataProvider<T, SerializablePredicate<T>>, 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(); + } + }; + private SerializableComparator<T> sortOrder = null; private SerializablePredicate<T> filter; @@ -376,4 +389,186 @@ public class ListDataProvider<T> SerializablePredicate<T> 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. + * <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 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. + * <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)); + }); + } } |