diff options
author | Teemu Suo-Anttila <teemusa@vaadin.com> | 2016-11-25 16:06:22 +0200 |
---|---|---|
committer | Ilia Motornyi <elmot@vaadin.com> | 2016-11-28 15:18:00 +0000 |
commit | 8310ada79e04d47e2118394b3c00a4fc90bd2fe4 (patch) | |
tree | 4473d1cd7503132fff8cae9ad57600f3a4100510 /server | |
parent | 302f870e302e9d8324e7cc6e8a5b6db41038db0a (diff) | |
download | vaadin-framework-8310ada79e04d47e2118394b3c00a4fc90bd2fe4.tar.gz vaadin-framework-8310ada79e04d47e2118394b3c00a4fc90bd2fe4.zip |
Add ComboBox custom filtering methods and tests
Change-Id: I640c6a7b3b8b89eff4b007d1cb70a25bbe28167e
Diffstat (limited to 'server')
3 files changed, 260 insertions, 0 deletions
diff --git a/server/src/main/java/com/vaadin/server/SerializableBiPredicate.java b/server/src/main/java/com/vaadin/server/SerializableBiPredicate.java new file mode 100644 index 0000000000..dd0635ca9d --- /dev/null +++ b/server/src/main/java/com/vaadin/server/SerializableBiPredicate.java @@ -0,0 +1,34 @@ +/* + * 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.server; + +import java.io.Serializable; +import java.util.function.BiPredicate; + +/** + * A {@link BiPredicate} that is also {@link Serializable}. + * + * @author Vaadin Ltd + * @since 8.0 + * @param <T> + * the type of the first input to the predicate + * @param <U> + * the type of the second input to the predicate + */ +public interface SerializableBiPredicate<T, U> + extends BiPredicate<T, U>, Serializable { + // Only method inherited from Function +} diff --git a/server/src/main/java/com/vaadin/ui/ComboBox.java b/server/src/main/java/com/vaadin/ui/ComboBox.java index 2b91236843..9399e1b129 100644 --- a/server/src/main/java/com/vaadin/ui/ComboBox.java +++ b/server/src/main/java/com/vaadin/ui/ComboBox.java @@ -39,6 +39,7 @@ import com.vaadin.event.FieldEvents.FocusListener; import com.vaadin.server.KeyMapper; import com.vaadin.server.Resource; import com.vaadin.server.ResourceReference; +import com.vaadin.server.SerializableBiPredicate; import com.vaadin.server.data.DataCommunicator; import com.vaadin.server.data.DataKeyMapper; import com.vaadin.server.data.DataProvider; @@ -255,6 +256,50 @@ public class ComboBox<T> extends AbstractSingleSelect<T> } /** + * Sets the data items of this listing and a simple string filter with which + * the item string and the text the user has input are compared. + * <p> + * Note that unlike {@link #setItems(Collection)}, no automatic case + * conversion is performed before the comparison. + * + * @param filterPredicate + * predicate for comparing the item string (first parameter) and + * the filter string (second parameter) + * @param items + * the data items to display + */ + public void setItems( + SerializableBiPredicate<String, String> filterPredicate, + Collection<T> items) { + DataProvider<T, String> provider = DataProvider.create(items) + .convertFilter(filterText -> item -> filterPredicate.test( + getItemCaptionGenerator().apply(item), filterText)); + setDataProvider(provider); + } + + /** + * Sets the data items of this listing and a simple string filter with which + * the item string and the text the user has input are compared. + * <p> + * Note that unlike {@link #setItems(Collection)}, no automatic case + * conversion is performed before the comparison. + * + * @param filterPredicate + * predicate for comparing the item string (first parameter) and + * the filter string (second parameter) + * @param items + * the data items to display + */ + public void setItems( + SerializableBiPredicate<String, String> filterPredicate, + @SuppressWarnings("unchecked") T... items) { + DataProvider<T, String> provider = DataProvider.create(items) + .convertFilter(filterText -> item -> filterPredicate.test( + getItemCaptionGenerator().apply(item), filterText)); + setDataProvider(provider); + } + + /** * Gets the current placeholder text shown when the combo box would be * empty. * diff --git a/server/src/test/java/com/vaadin/tests/server/component/combobox/ComboBoxFilteringTest.java b/server/src/test/java/com/vaadin/tests/server/component/combobox/ComboBoxFilteringTest.java new file mode 100644 index 0000000000..54ea367fca --- /dev/null +++ b/server/src/test/java/com/vaadin/tests/server/component/combobox/ComboBoxFilteringTest.java @@ -0,0 +1,181 @@ +/* + * 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.tests.server.component.combobox; + +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.server.data.DataProvider; +import com.vaadin.server.data.ListDataProvider; +import com.vaadin.server.data.Query; +import com.vaadin.tests.data.bean.Person; +import com.vaadin.tests.data.bean.Sex; +import com.vaadin.ui.ComboBox; + +/** + * Test for ComboBox data providers and filtering. + * + * @author Vaadin Ltd + */ +public class ComboBoxFilteringTest { + private static final String[] PERSON_NAMES = new String[] { + "Enrique Iglesias", "Henry Dunant", "Erwin Engelbrecht" }; + + private ComboBox<Person> comboBox; + + @Before + public void setup() { + comboBox = new ComboBox<>(); + comboBox.setLocale(Locale.US); + } + + @Test + public void setItems_array_defaultFiltering() { + comboBox.setItemCaptionGenerator(Person::getFirstName); + + // Result: typing "en" into the search field finds "Enrique Iglesias" + // and "Henry Dunant", but not "Erwin Engelbrecht" + comboBox.setItems(getPersonArray()); + + checkFiltering("en", "ennen", 3, 2); + } + + @Test + public void setItems_array_setItemCaptionAfterItems() { + // Result: typing "en" into the search field finds "Enrique Iglesias" + // and "Henry Dunant", but not "Erwin Engelbrecht" + comboBox.setItems(getPersonArray()); + + // It shouldn't matter if this is done before or after setItems + comboBox.setItemCaptionGenerator(Person::getFirstName); + + checkFiltering("en", "ennen", 3, 2); + } + + @Test + public void setItems_collection_defaultFiltering() { + comboBox.setItemCaptionGenerator(Person::getFirstName); + + // Result: typing "en" into the search field finds "Enrique Iglesias" + // and "Henry Dunant", but not "Erwin Engelbrecht" + comboBox.setItems(getPersonCollection()); + + checkFiltering("en", "ennen", 3, 2); + } + + @Test + public void setItems_collection_setItemCaptionAfterItems() { + // Result: typing "en" into the search field finds "Enrique Iglesias" + // and "Henry Dunant", but not "Erwin Engelbrecht" + comboBox.setItems(getPersonCollection()); + + // It shouldn't matter if this is done before or after setItems + comboBox.setItemCaptionGenerator(Person::getFirstName); + + checkFiltering("en", "ennen", 3, 2); + } + + @Test + public void setItems_array_customFiltering() { + comboBox.setItemCaptionGenerator(Person::getFirstName); + + // Result: typing "en" into the search field finds "Enrique Iglesias" + // and "Henry Dunant", but not "Erwin Engelbrecht" + comboBox.setItems(String::startsWith, getPersonArray()); + + checkFiltering("Er", "er", 3, 1); + } + + @Test + public void setItems_collection_customFiltering() { + comboBox.setItemCaptionGenerator(Person::getFirstName); + + // Result: typing "en" into the search field finds "Enrique Iglesias" + // and "Henry Dunant", but not "Erwin Engelbrecht" + comboBox.setItems(String::startsWith, getPersonCollection()); + + checkFiltering("Er", "er", 3, 1); + } + + public void invalid_dataProvider_compile_error() { + // uncommenting this causes a compile time error + ListDataProvider<Person> ldp = DataProvider.create(getPersonArray()); + // Compile error, because of invalid data provider filter type + // comboBox.setDataProvider(ldp); + } + + @Test + public void customDataProvider_filterByLastName() { + comboBox.setItemCaptionGenerator(Person::getFirstName); + + // Filters by last name, regardless of the item caption generator + ListDataProvider<Person> ldp = DataProvider.create(getPersonArray()); + comboBox.setDataProvider(ldp.convertFilter( + text -> person -> person.getLastName().contains(text))); + + checkFiltering("u", "ab", 3, 1); + } + + @Test + public void customDataProvider_filterByLastNameWithAccessRestriction() { + comboBox.setItemCaptionGenerator(Person::getFirstName); + + // Filters by last name, regardless of the item caption generator + ListDataProvider<Person> ldp = DataProvider.create(getPersonArray()); + // Same as above, but only showing a subset of the persons + comboBox.setDataProvider(ldp + .applyFilter(person -> person.getFirstName().contains("nr")) + .convertFilter( + text -> person -> person.getLastName().contains(text))); + + checkFiltering("t", "Engel", 2, 1); + } + + private void checkFiltering(String filterText, String nonMatchingFilterText, + int totalMatches, int matchingResults) { + DataProvider<Person, String> dataProvider = comboBox.getDataProvider(); + + Assert.assertEquals( + "ComboBox filtered out results with no filter applied", + totalMatches, dataProvider.size(new Query<String>())); + Assert.assertEquals( + "ComboBox filtered out results with empty filter string", + totalMatches, dataProvider.size(new Query<String>(""))); + Assert.assertEquals("ComboBox filtered out wrong number of results", + matchingResults, + dataProvider.size(new Query<String>(filterText))); + Assert.assertEquals( + "ComboBox should have no results with a non-matching filter", 0, + dataProvider.size(new Query<String>(nonMatchingFilterText))); + } + + private List<Person> getPersonCollection() { + return Stream + .of(PERSON_NAMES).map(name -> new Person(name.split(" ")[0], + name.split(" ")[1], null, 0, Sex.MALE, null)) + .collect(Collectors.toList()); + } + + private Person[] getPersonArray() { + return getPersonCollection().toArray(new Person[PERSON_NAMES.length]); + } +} |