import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;
-import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import com.vaadin.data.util.BeanUtil;
import com.vaadin.data.util.converter.Converter;
import com.vaadin.data.validator.BeanValidator;
-import com.vaadin.ui.AbstractMultiSelect;
-import com.vaadin.ui.AbstractSingleSelect;
import com.vaadin.util.ReflectTools;
/**
this::handleValidationStatus);
}
- @Override
- public <SELECTVALUE> BeanBinding<BEAN, SELECTVALUE, SELECTVALUE> forSelect(
- AbstractSingleSelect<SELECTVALUE> select) {
- return (BeanBinding<BEAN, SELECTVALUE, SELECTVALUE>) super.forSelect(
- select);
- }
-
- @Override
- public <SELECTVALUE> BeanBinding<BEAN, Set<SELECTVALUE>, Set<SELECTVALUE>> forSelect(
- AbstractMultiSelect<SELECTVALUE> select) {
- return (BeanBinding<BEAN, Set<SELECTVALUE>, Set<SELECTVALUE>>) super.forSelect(
- select);
- }
-
/**
* Binds the given field to the property with the given name. The getter and
* setter methods of the property are looked up with bean introspection and
import com.vaadin.server.ErrorMessage;
import com.vaadin.server.UserError;
import com.vaadin.shared.Registration;
-import com.vaadin.shared.data.selection.SelectionModel.Multi;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.AbstractMultiSelect;
-import com.vaadin.ui.AbstractSingleSelect;
import com.vaadin.ui.Component;
import com.vaadin.ui.Label;
import com.vaadin.ui.UI;
this::handleValidationStatus);
}
- /**
- * Creates a new binding for the given single select component. The returned
- * binding may be further configured before invoking
- * {@link Binding#bind(Function, BiConsumer) Binding.bind} which completes
- * the binding. Until {@code Binding.bind} is called, the binding has no
- * effect.
- *
- * @param <SELECTVALUE>
- * the bean type of the select
- * @param select
- * the select to be bound, not null
- * @return the new binding
- *
- * @see #bind(AbstractSingleSelect, Function, BiConsumer)
- */
- public <SELECTVALUE> Binding<BEAN, SELECTVALUE, SELECTVALUE> forSelect(
- AbstractSingleSelect<SELECTVALUE> select) {
- return forField(new HasValue<SELECTVALUE>() {
-
- @Override
- public void setValue(SELECTVALUE value) {
- select.setSelectedItem(value);
- }
-
- @Override
- public SELECTVALUE getValue() {
- return select.getSelectedItem().orElse(null);
- }
-
- @Override
- public Registration addValueChangeListener(
- ValueChangeListener<? super SELECTVALUE> listener) {
- return select.addSelectionListener(
- e -> listener.accept(new ValueChange<>(select,
- getValue(), e.isUserOriginated())));
- }
- });
- }
-
- /**
- * Creates a new binding for the given multi select component. The returned
- * binding may be further configured before invoking
- * {@link Binding#bind(Function, BiConsumer) Binding.bind} which completes
- * the binding. Until {@code Binding.bind} is called, the binding has no
- * effect.
- *
- * @param <SELECTVALUE>
- * the bean type of the select
- * @param select
- * the select to be bound, not null
- * @return the new binding
- */
- public <SELECTVALUE> Binding<BEAN, Set<SELECTVALUE>, Set<SELECTVALUE>> forSelect(
- AbstractMultiSelect<SELECTVALUE> select) {
- return forField(new HasValue<Set<SELECTVALUE>>() {
-
- @Override
- public void setValue(Set<SELECTVALUE> value) {
- Multi<SELECTVALUE> selectionModel = select.getSelectionModel();
- selectionModel.deselectAll();
- value.forEach(selectionModel::select);
- }
-
- @Override
- public Set<SELECTVALUE> getValue() {
- return select.getSelectionModel().getSelectedItems();
- }
-
- @Override
- public Registration addValueChangeListener(
- ValueChangeListener<? super Set<SELECTVALUE>> listener) {
- return select.addSelectionListener(
- e -> listener.accept(new ValueChange<>(select,
- getValue(), e.isUserOriginated())));
- }
- });
- }
-
/**
* Binds a field to a bean property represented by the given getter and
* setter pair. The functions are used to update the field value from the
forField(field).bind(getter, setter);
}
- /**
- * Binds a single select to a bean property represented by the given getter
- * and setter pair. The functions are used to update the selection from the
- * property and to store the selection to the property, respectively.
- * <p>
- * Use the {@link #forSelect(AbstractSingleSelect)} method instead if you
- * want to further configure the new binding.
- * <p>
- * When a bean is bound with {@link Binder#bind(BEAN)}, the selected bean is
- * set to the return value of the given getter. The property value is then
- * updated via the given setter whenever the selected bean changes. The
- * setter may be null; in that case the property value is never updated and
- * the binding is said to be <i>read-only</i>. A null property value
- * corresponds to no selection and vice versa.
- * <p>
- * If the Binder is already bound to some bean, the newly bound select is
- * associated with the corresponding bean property as described above.
- * <p>
- * The getter and setter can be arbitrary functions, for instance
- * implementing user-defined conversion or validation. However, in the most
- * basic use case you can simply pass a pair of method references to this
- * method as follows:
- *
- * <pre>
- * class Person {
- * public enum Title { MR, MS, MISS, MRS, DR, PROF };
- *
- * public Title getTitle() { ... }
- * public void setTitle(Title title) { ... }
- * }
- *
- * NativeSelect<Title> titleSelect = new NativeSelect<>();
- * titleSelect.setItems(Title.values());
- * binder.bind(titleSelect, Person::getTitle, Person::setTitle);
- * </pre>
- *
- * @param <SELECTVALUE>
- * the bean type of the select
- * @param select
- * the select to bind, not null
- * @param getter
- * the function to get the value of the property to the
- * selection, not null
- * @param setter
- * the function to save the selection to the property or null if
- * read-only
- */
- public <SELECTVALUE> void bind(AbstractSingleSelect<SELECTVALUE> select,
- Function<BEAN, SELECTVALUE> getter,
- BiConsumer<BEAN, SELECTVALUE> setter) {
- forSelect(select).bind(getter, setter);
- }
-
- /**
- * Binds a multi select to a bean property represented by the given getter
- * and setter pair. The functions are used to update the set of selected
- * beans from the property and to store the selection to the property,
- * respectively.
- * <p>
- * Use the {@link #forSelect(AbstractMultiSelect)} method instead if you
- * want to further configure the new binding.
- * <p>
- * When a bean is bound with {@link Binder#bind(BEAN)}, the set of selected
- * beans are set to the return value of the given getter. The property value
- * is then updated via the given setter whenever the selected beans change.
- * The setter may be null; in that case the property value is never updated
- * and the binding is said to be <i>read-only</i>.
- * <p>
- * If the Binder is already bound to some bean, the newly bound select is
- * associated with the corresponding bean property as described above.
- * <p>
- * The getter and setter can be arbitrary functions, for instance
- * implementing user-defined conversion or validation. However, in the most
- * basic use case you can simply pass a pair of method references to this
- * method as follows:
- *
- * <pre>
- * class Feature {
- * public enum Browser { CHROME, EDGE, FIREFOX, IE, OPERA, SAFARI }
-
- * public Set<Browser> getSupportedBrowsers() { ... }
- * public void setSupportedBrowsers(Set<Browser> title) { ... }
- * }
- *
- * CheckBoxGroup<Title> browserSelect = new CheckBoxGroup<>();
- * browserSelect.setItems(Browser.values());
- * binder.bind(browserSelect, Feature::getSupportedBrowsers, Feature::setSupportedBrowsers);
- * </pre>
- *
- * @param <SELECTVALUE>
- * the bean type of the select
- * @param select
- * the select to bind, not null
- * @param getter
- * the function to get the set of selected beans, not null
- * @param setter
- * the function to save the set of selected beans or null if
- * read-only
- */
- public <SELECTVALUE> void bind(AbstractMultiSelect<SELECTVALUE> select,
- Function<BEAN, Set<SELECTVALUE>> getter,
- BiConsumer<BEAN, Set<SELECTVALUE>> setter) {
- forSelect(select).bind(getter, setter);
- }
-
/**
* Binds the given bean to all the fields added to this Binder. To remove
* the binding, call {@link #unbind()}.
* @see Registration
*/
@FunctionalInterface
- public interface ValueChangeListener<V> extends
- EventListener<ValueChange<V>> {
+ public interface ValueChangeListener<V>
+ extends EventListener<ValueChange<V>> {
@Deprecated
public static final Method VALUE_CHANGE_METHOD = ReflectTools
/**
* Adds a value change listener. The listener is called when the value of
- * this {@code hasValue} is changed either by the user or programmatically.
+ * this {@code HasValue} is changed either by the user or programmatically.
*
* @param listener
* the value change listener, not null
import java.util.function.Predicate;
import java.util.stream.Collectors;
+import com.vaadin.data.HasValue;
import com.vaadin.event.selection.MultiSelectionEvent;
import com.vaadin.event.selection.MultiSelectionListener;
import com.vaadin.server.Resource;
* @since 8.0
*/
public abstract class AbstractMultiSelect<T>
- extends AbstractListing<T, Multi<T>> {
+ extends AbstractListing<T, Multi<T>> implements HasValue<Set<T>> {
/**
* Simple implementation of multiselectmodel.
getDataCommunicator().reset();
}
+ /**
+ * Returns the current value of this object which is an immutable set of the
+ * currently selected items.
+ * <p>
+ * The call is delegated to {@link #getSelectedItems()}
+ *
+ * @return the current selection
+ *
+ * @see #getSelectedItems()
+ * @see SelectionModel#getSelectedItems
+ */
+ @Override
+ public Set<T> getValue() {
+ return getSelectedItems();
+ }
+
+ /**
+ * Sets the value of this object which is a set of items to select. If the
+ * new value is not equal to {@code getValue()}, fires a value change event.
+ * May throw {@code IllegalArgumentException} if the value is not
+ * acceptable.
+ * <p>
+ * The method effectively selects the given items and deselects previously
+ * selected. The call is delegated to
+ * {@link Multi#updateSelection(Set, Set)}.
+ *
+ * @see Multi#updateSelection(Set, Set)
+ *
+ * @param value
+ * the items to select, not {@code null}
+ * @throws IllegalArgumentException
+ * if the value is invalid
+ */
+ @Override
+ public void setValue(Set<T> value) {
+ Objects.requireNonNull(value);
+ Set<T> copy = value.stream().map(Objects::requireNonNull)
+ .collect(Collectors.toCollection(LinkedHashSet::new));
+
+ getSelectionModel().updateSelection(copy,
+ new LinkedHashSet<>(getSelectionModel().getSelectedItems()));
+ }
+
+ /**
+ * Adds a value change listener. The listener is called when the selection
+ * set of this multi select is changed either by the user or
+ * programmatically.
+ *
+ * @see #addSelectionListener(MultiSelectionListener)
+ *
+ * @param listener
+ * the value change listener, not null
+ * @return a registration for the listener
+ */
+ @Override
+ public Registration addValueChangeListener(
+ HasValue.ValueChangeListener<? super Set<T>> listener) {
+ return addSelectionListener(
+ event -> listener.accept(new ValueChange<>(event.getConnector(),
+ event.getValue(), event.isUserOriginated())));
+ }
+
/**
* Returns the item icon generator for this multiselect.
* <p>
import java.util.Objects;
import java.util.Optional;
+import com.vaadin.data.HasValue;
import com.vaadin.event.selection.SingleSelectionChange;
import com.vaadin.event.selection.SingleSelectionListener;
import com.vaadin.server.data.DataCommunicator;
import com.vaadin.shared.Registration;
import com.vaadin.shared.data.selection.SelectionModel;
+import com.vaadin.shared.data.selection.SelectionModel.Single;
import com.vaadin.shared.data.selection.SelectionServerRpc;
import com.vaadin.shared.ui.AbstractSingleSelectState;
import com.vaadin.util.ReflectTools;
* @since 8.0
*/
public abstract class AbstractSingleSelect<T> extends
- AbstractListing<T, AbstractSingleSelect<T>.AbstractSingleSelection> {
+ AbstractListing<T, AbstractSingleSelect<T>.AbstractSingleSelection>
+ implements HasValue<T> {
/**
* A base class for single selection model implementations. Listens to
getSelectionModel().setSelectedItem(item);
}
+ /**
+ * Returns the current value of this object which is the currently selected
+ * item.
+ * <p>
+ * The call is delegated to {@link #getSelectedItem()}
+ *
+ * @return the current selection, may be {@code null}
+ *
+ * @see #getSelectedItem()
+ * @see Single#getSelectedItem
+ */
+ @Override
+ public T getValue() {
+ return getSelectedItem().orElse(null);
+ }
+
+ /**
+ * Sets the value of this object which is an item to select. If the new
+ * value is not equal to {@code getValue()}, fires a value change event. If
+ * value is {@code null} then it deselects currently selected item.
+ * <p>
+ * The call is delegated to {@link #setSelectedItem(Object)}.
+ *
+ * @see #setSelectedItem(Object)
+ * @see Single#setSelectedItem(Object)
+ *
+ * @param value
+ * the item to select or {@code null} to clear selection
+ */
+ @Override
+ public void setValue(T value) {
+ setSelectedItem(value);
+ }
+
+ @Override
+ public Registration addValueChangeListener(
+ HasValue.ValueChangeListener<? super T> listener) {
+ return addSelectionListener(
+ event -> listener.accept(new ValueChange<>(event.getConnector(),
+ event.getValue(), event.isUserOriginated())));
+ }
+
@Override
protected AbstractSingleSelectState getState() {
return (AbstractSingleSelectState) super.getState();
select = new CheckBoxGroup<>();
select.setItems(TestEnum.values());
- converterBinder.forSelect(select)
+ converterBinder.forField(select)
.withConverter(new TestEnumSetToStringConverter())
.bind(AtomicReference<String>::get,
AtomicReference<String>::set);
public void beanBound_bindSelect_selectionUpdated() {
item.setEnums(Collections.singleton(TestEnum.TWO));
binder.bind(item);
- binder.forSelect(select).bind(BeanWithEnums::getEnums,
+ binder.forField(select).bind(BeanWithEnums::getEnums,
BeanWithEnums::setEnums);
assertEquals(Collections.singleton(TestEnum.TWO),
@Test
public void withValidator_validate_validatorUsed() {
- binder.forSelect(select)
+ binder.forField(select)
.withValidator(selection -> selection.size() % 2 == 1,
"Must select odd number of items")
.bind(BeanWithEnums::getEnums, BeanWithEnums::setEnums);
}
protected void bindEnum() {
- binder.forSelect(select).bind(BeanWithEnums::getEnums,
+ binder.forField(select).bind(BeanWithEnums::getEnums,
BeanWithEnums::setEnums);
binder.bind(item);
}
import com.vaadin.tests.data.bean.Sex;
import com.vaadin.ui.NativeSelect;
-public class BinderSingleSelectTest extends
- BinderTestBase<Binder<Person>, Person> {
+public class BinderSingleSelectTest
+ extends BinderTestBase<Binder<Person>, Person> {
private NativeSelect<Sex> select;
public void personBound_bindSelect_selectionUpdated() {
item.setSex(Sex.MALE);
binder.bind(item);
- binder.forSelect(select).bind(Person::getSex, Person::setSex);
+ binder.forField(select).bind(Person::getSex, Person::setSex);
assertSame(Sex.MALE, select.getSelectedItem().orElse(null));
}
}
protected void bindSex() {
- binder.forSelect(select).bind(Person::getSex, Person::setSex);
+ binder.forField(select).bind(Person::getSex, Person::setSex);
binder.bind(item);
}
}
TwinColSelect<String> s = new TwinColSelect<>();
s.setRightColumnCaption("Selected values");
s.setLeftColumnCaption("Unselected values");
- s.setItems("First item", "Second item", "Third item");
- s.getSelectionModel().select("Second item");
- s.getSelectionModel().select("Third item");
+ /*
+ * This is broken for now : declarative doesn't read data and doesn't
+ * set value/selection. See #388
+ *
+ * s.setItems("First item", "Second item", "Third item");
+ * s.getSelectionModel().select("Second item");
+ * s.getSelectionModel().select("Third item");
+ *
+ */
s.setRows(5);
return s;
}
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.LinkedHashSet;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
+import org.mockito.Mockito;
+import com.vaadin.data.HasValue.ValueChange;
+import com.vaadin.event.selection.MultiSelectionEvent;
+import com.vaadin.event.selection.MultiSelectionListener;
import com.vaadin.server.data.DataSource;
import com.vaadin.shared.Registration;
import com.vaadin.shared.data.selection.MultiSelectServerRpc;
assertSelectionOrder(selectionModel, "6", "4", "8");
}
+ @Test
+ public void getValue() {
+ selectionModel.selectItems("1");
+
+ Assert.assertEquals(Collections.singleton("1"),
+ selectToTest.getValue());
+
+ selectionModel.deselectAll();
+ LinkedHashSet<String> set = new LinkedHashSet<>();
+ set.add("1");
+ set.add("5");
+ selectionModel.selectItems(set.toArray(new String[2]));
+ Assert.assertEquals(set, selectToTest.getValue());
+
+ set.add("3");
+ selectionModel.selectItems("3");
+ Assert.assertEquals(set, selectToTest.getValue());
+ }
+
+ @Test
+ @SuppressWarnings({ "serial", "unchecked" })
+ public void getValue_isDelegatedTo_getSelectedItems() {
+ Set<String> set = Mockito.mock(Set.class);
+ AbstractMultiSelect<String> select = new AbstractMultiSelect<String>() {
+
+ @Override
+ public Set<String> getSelectedItems() {
+ return set;
+ }
+ };
+
+ Assert.assertSame(set, select.getValue());
+ }
+
+ @Test
+ public void setValue() {
+ selectToTest.setValue(Collections.singleton("1"));
+
+ Assert.assertEquals(Collections.singleton("1"),
+ selectionModel.getSelectedItems());
+
+ Set<String> set = new LinkedHashSet<>();
+ set.add("4");
+ set.add("3");
+ selectToTest.setValue(set);
+
+ Assert.assertEquals(set, selectionModel.getSelectedItems());
+ }
+
+ @Test
+ @SuppressWarnings({ "unchecked", "rawtypes", "serial" })
+ public void setValue_isDelegatedToDeselectAndUpdateSelection() {
+ Multi<?> model = Mockito.mock(Multi.class);
+ AbstractMultiSelect<String> select = new AbstractMultiSelect<String>() {
+ @Override
+ public Multi<String> getSelectionModel() {
+ return (Multi<String>) model;
+ }
+ };
+
+ Set set = new LinkedHashSet<>();
+ set.add("foo1");
+ set.add("foo");
+ Set selected = new LinkedHashSet<>();
+ selected.add("bar1");
+ selected.add("bar");
+ selected.add("bar2");
+ Mockito.when(model.getSelectedItems()).thenReturn(selected);
+
+ select.setValue(set);
+
+ Mockito.verify(model).updateSelection(set, selected);
+ }
+
+ @SuppressWarnings({ "unchecked", "serial" })
+ @Test
+ public void addValueChangeListener() {
+ AtomicReference<MultiSelectionListener<String>> selectionListener = new AtomicReference<>();
+ Registration registration = Mockito.mock(Registration.class);
+ AbstractMultiSelect<String> select = new AbstractMultiSelect<String>() {
+ @Override
+ public Registration addSelectionListener(
+ MultiSelectionListener<String> listener) {
+ selectionListener.set(listener);
+ return registration;
+ }
+ };
+
+ AtomicReference<ValueChange<?>> event = new AtomicReference<>();
+ Registration actualRegistration = select.addValueChangeListener(evt -> {
+ Assert.assertNull(event.get());
+ event.set(evt);
+ });
+
+ Assert.assertSame(registration, actualRegistration);
+
+ Set<String> set = new HashSet<>();
+ set.add("foo");
+ set.add("bar");
+ selectionListener.get().accept(new MultiSelectionEvent<>(select,
+ Mockito.mock(Set.class), set, true));
+
+ Assert.assertEquals(select, event.get().getConnector());
+ Assert.assertEquals(set, event.get().getValue());
+ Assert.assertTrue(event.get().isUserOriginated());
+ }
+
private void rpcSelect(String... keysToSelect) {
rpcUpdateSelection(keysToSelect, new String[] {});
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.Mockito;
+import com.vaadin.data.HasValue.ValueChange;
+import com.vaadin.event.selection.SingleSelectionChange;
+import com.vaadin.event.selection.SingleSelectionListener;
import com.vaadin.server.data.datasource.bov.Person;
+import com.vaadin.shared.Registration;
import com.vaadin.shared.data.DataCommunicatorClientRpc;
+import com.vaadin.shared.data.selection.SelectionModel.Multi;
import com.vaadin.ui.AbstractSingleSelect.AbstractSingleSelection;
/**
private PersonListing.AbstractSingleSelection selectionModel;
private List<Person> selectionChanges;
- private static class PersonListing extends
- AbstractSingleSelect<Person> {
+ private static class PersonListing extends AbstractSingleSelect<Person> {
public PersonListing() {
setSelectionModel(new SimpleSingleSelection());
}
assertTrue(selectionModel.isSelected(PERSON_B));
assertFalse(selectionModel.isSelected(PERSON_C));
- assertEquals(Collections.singleton(PERSON_B), selectionModel
- .getSelectedItems());
+ assertEquals(Collections.singleton(PERSON_B),
+ selectionModel.getSelectedItems());
assertEquals(Arrays.asList(PERSON_B), selectionChanges);
}
assertFalse(selectionModel.isSelected(PERSON_B));
assertTrue(selectionModel.isSelected(PERSON_C));
- assertEquals(Collections.singleton(PERSON_C), selectionModel
- .getSelectedItems());
+ assertEquals(Collections.singleton(PERSON_C),
+ selectionModel.getSelectedItems());
assertEquals(Arrays.asList(PERSON_B, PERSON_C), selectionChanges);
}
assertFalse(selectionModel.isSelected(PERSON_B));
assertTrue(selectionModel.isSelected(PERSON_C));
- assertEquals(Collections.singleton(PERSON_C), selectionModel
- .getSelectedItems());
+ assertEquals(Collections.singleton(PERSON_C),
+ selectionModel.getSelectedItems());
assertEquals(Arrays.asList(PERSON_C), selectionChanges);
}
assertFalse(selectionModel.isSelected(PERSON_B));
assertTrue(selectionModel.isSelected(PERSON_C));
- assertEquals(Collections.singleton(PERSON_C), selectionModel
- .getSelectedItems());
+ assertEquals(Collections.singleton(PERSON_C),
+ selectionModel.getSelectedItems());
assertEquals(Arrays.asList(PERSON_C), selectionChanges);
}
assertEquals(Arrays.asList(PERSON_C, null), selectionChanges);
}
+ @Test
+ public void getValue() {
+ selectionModel.setSelectedItem(PERSON_B);
+
+ Assert.assertEquals(PERSON_B, listing.getValue());
+
+ selectionModel.deselectAll();
+ Assert.assertNull(listing.getValue());
+ }
+
+ @Test
+ @SuppressWarnings({ "rawtypes" })
+ public void getValue_isDelegatedTo_getSelectedItem() {
+ AbstractSingleSelect select = Mockito.mock(AbstractSingleSelect.class);
+ Optional selected = Optional.of(new Object());
+ Mockito.when(select.getSelectedItem()).thenReturn(selected);
+ Mockito.doCallRealMethod().when(select).getValue();
+
+ Assert.assertSame(selected.get(), select.getValue());
+
+ selected = Optional.empty();
+ Mockito.when(select.getSelectedItem()).thenReturn(selected);
+ Assert.assertNull(select.getValue());
+ }
+
+ @Test
+ public void setValue() {
+ listing.setValue(PERSON_C);
+
+ Assert.assertEquals(PERSON_C, selectionModel.getSelectedItem().get());
+
+ listing.setValue(null);
+
+ Assert.assertFalse(selectionModel.getSelectedItem().isPresent());
+ }
+
+ @Test
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public void setValue_isDelegatedTo_setSelectedItem() {
+ AbstractSingleSelect select = Mockito.mock(AbstractSingleSelect.class);
+ Mockito.doCallRealMethod().when(select).setValue(Mockito.any());
+
+ Object value = new Object();
+ select.setValue(value);
+ Mockito.verify(select).setSelectedItem(value);
+
+ select.setValue(null);
+ Mockito.verify(select).setSelectedItem(null);
+ }
+
+ @SuppressWarnings({ "unchecked", "serial" })
+ @Test
+ public void addValueChangeListener() {
+ AtomicReference<SingleSelectionListener<String>> selectionListener = new AtomicReference<>();
+ Registration registration = Mockito.mock(Registration.class);
+ AbstractSingleSelect<String> select = new AbstractSingleSelect<String>() {
+ @Override
+ public Registration addSelectionListener(
+ SingleSelectionListener<String> listener) {
+ selectionListener.set(listener);
+ return registration;
+ }
+ };
+
+ AtomicReference<ValueChange<?>> event = new AtomicReference<>();
+ Registration actualRegistration = select.addValueChangeListener(evt -> {
+ Assert.assertNull(event.get());
+ event.set(evt);
+ });
+ Assert.assertSame(registration, actualRegistration);
+
+ String value = "foo";
+ selectionListener.get()
+ .accept(new SingleSelectionChange<>(select, value, true));
+
+ Assert.assertEquals(select, event.get().getConnector());
+ Assert.assertEquals(value, event.get().getValue());
+ Assert.assertTrue(event.get().isUserOriginated());
+ }
+
+ @Test
+ @SuppressWarnings({ "unchecked", "rawtypes", "serial" })
+ public void setValue_isDelegatedToDeselectAndUpdateSelection() {
+ Multi<?> model = Mockito.mock(Multi.class);
+ AbstractMultiSelect<String> select = new AbstractMultiSelect<String>() {
+ @Override
+ public Multi<String> getSelectionModel() {
+ return (Multi<String>) model;
+ }
+ };
+
+ Set set = new LinkedHashSet<>();
+ set.add("foo1");
+ set.add("foo");
+ Set selected = new LinkedHashSet<>();
+ selected.add("bar1");
+ selected.add("bar");
+ selected.add("bar2");
+ Mockito.when(model.getSelectedItems()).thenReturn(selected);
+
+ select.setValue(set);
+
+ Mockito.verify(model).updateSelection(set, selected);
+ }
+
}