Browse Source

Add ComboBox custom filtering methods and tests

Change-Id: I640c6a7b3b8b89eff4b007d1cb70a25bbe28167e
tags/8.0.0.alpha8
Teemu Suo-Anttila 7 years ago
parent
commit
8310ada79e

+ 34
- 0
server/src/main/java/com/vaadin/server/SerializableBiPredicate.java View File

@@ -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
}

+ 45
- 0
server/src/main/java/com/vaadin/ui/ComboBox.java View File

@@ -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;
@@ -254,6 +255,50 @@ public class ComboBox<T> extends AbstractSingleSelect<T>
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,
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.

+ 181
- 0
server/src/test/java/com/vaadin/tests/server/component/combobox/ComboBoxFilteringTest.java View File

@@ -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]);
}
}

Loading…
Cancel
Save