aboutsummaryrefslogtreecommitdiffstats
path: root/server/src
diff options
context:
space:
mode:
authorDenis Anisimov <denis@vaadin.com>2016-11-02 14:16:53 +0200
committerVaadin Code Review <review@vaadin.com>2016-11-04 12:02:50 +0000
commitb6960abff449a5cf6cb858f3102bc37dfab3fcc2 (patch)
tree5d6817b78db68ec377278126c5c205cc00cf3f44 /server/src
parent9e10d5d29cc091f7bab62091ebf955891ec28188 (diff)
downloadvaadin-framework-b6960abff449a5cf6cb858f3102bc37dfab3fcc2.tar.gz
vaadin-framework-b6960abff449a5cf6cb858f3102bc37dfab3fcc2.zip
Create MultiSelect interface to replace Multi selection model.
Fixes vaadin/framework8-issues#423 Change-Id: Ifd252b8feed323708a7ae73af2b836832570d192
Diffstat (limited to 'server/src')
-rw-r--r--server/src/main/java/com/vaadin/data/Listing.java63
-rw-r--r--server/src/main/java/com/vaadin/event/selection/SingleSelectionChangeEvent.java4
-rw-r--r--server/src/main/java/com/vaadin/ui/AbstractListing.java37
-rw-r--r--server/src/main/java/com/vaadin/ui/AbstractMultiSelect.java280
-rw-r--r--server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java336
-rw-r--r--server/src/main/java/com/vaadin/ui/ComboBox.java49
-rw-r--r--server/src/main/java/com/vaadin/ui/Grid.java164
-rw-r--r--server/src/main/java/com/vaadin/ui/MultiSelect.java139
-rw-r--r--server/src/main/java/com/vaadin/ui/NativeSelect.java2
-rw-r--r--server/src/main/java/com/vaadin/ui/RadioButtonGroup.java3
-rw-r--r--server/src/test/java/com/vaadin/data/BinderMultiSelectTest.java2
-rw-r--r--server/src/test/java/com/vaadin/tests/components/grid/GridSelectionTest.java24
-rw-r--r--server/src/test/java/com/vaadin/ui/AbstractListingTest.java4
-rw-r--r--server/src/test/java/com/vaadin/ui/AbstractMultiSelectTest.java118
-rw-r--r--server/src/test/java/com/vaadin/ui/AbstractSingleSelectTest.java122
-rw-r--r--server/src/test/java/com/vaadin/ui/RadioButtonGroupTest.java5
16 files changed, 721 insertions, 631 deletions
diff --git a/server/src/main/java/com/vaadin/data/Listing.java b/server/src/main/java/com/vaadin/data/Listing.java
index 397272a677..422b3a1128 100644
--- a/server/src/main/java/com/vaadin/data/Listing.java
+++ b/server/src/main/java/com/vaadin/data/Listing.java
@@ -17,7 +17,6 @@ package com.vaadin.data;
import java.io.Serializable;
import java.util.Collection;
-import java.util.Set;
import com.vaadin.server.data.DataSource;
@@ -28,12 +27,9 @@ import com.vaadin.server.data.DataSource;
*
* @param <T>
* the item data type
- * @param <SELECTIONMODEL>
- * the selection logic supported by this listing
* @since 8.0
*/
-public interface Listing<T, SELECTIONMODEL extends SelectionModel<T>>
- extends Serializable {
+public interface Listing<T> extends Serializable {
/**
* Returns the source of data items used by this listing.
@@ -52,13 +48,6 @@ public interface Listing<T, SELECTIONMODEL extends SelectionModel<T>>
void setDataSource(DataSource<T> dataSource);
/**
- * Returns the selection model for this listing.
- *
- * @return the selection model, not null
- */
- SELECTIONMODEL getSelectionModel();
-
- /**
* Sets the collection of data items of this listing.
*
* @param items
@@ -79,54 +68,4 @@ public interface Listing<T, SELECTIONMODEL extends SelectionModel<T>>
setDataSource(DataSource.create(items));
}
- /* SelectionModel helper methods */
-
- /**
- * Returns an immutable set of the currently selected items. The iteration
- * order of the items in the returned set is specified by the
- * {@linkplain #getSelectionModel() selection model} used.
- *
- * @return the current selection
- *
- * @see SelectionModel#getSelectedItems
- */
- default Set<T> getSelectedItems() {
- return getSelectionModel().getSelectedItems();
- }
-
- /**
- * Selects the given item. If the item is already selected, does nothing.
- *
- * @param item
- * the item to select, not null
- *
- * @see SelectionModel#select
- */
- default void select(T item) {
- getSelectionModel().select(item);
- }
-
- /**
- * Deselects the given item. If the item is not currently selected, does
- * nothing.
- *
- * @param item
- * the item to deselect, not null
- *
- * @see SelectionModel#deselect
- */
- default void deselect(T item) {
- getSelectionModel().deselect(item);
- }
-
- /**
- * Returns whether the given item is currently selected.
- *
- * @param item
- * the item to check, not null
- * @return {@code true} if the item is selected, {@code false} otherwise
- */
- default boolean isSelected(T item) {
- return getSelectionModel().isSelected(item);
- }
}
diff --git a/server/src/main/java/com/vaadin/event/selection/SingleSelectionChangeEvent.java b/server/src/main/java/com/vaadin/event/selection/SingleSelectionChangeEvent.java
index 566facfd9c..7f1acff82b 100644
--- a/server/src/main/java/com/vaadin/event/selection/SingleSelectionChangeEvent.java
+++ b/server/src/main/java/com/vaadin/event/selection/SingleSelectionChangeEvent.java
@@ -67,8 +67,8 @@ public class SingleSelectionChangeEvent<T> extends ValueChangeEvent<T>
@Override
@SuppressWarnings("unchecked")
- public AbstractListing<T, ?> getComponent() {
- return (AbstractListing<T, ?>) super.getComponent();
+ public AbstractListing<T> getComponent() {
+ return (AbstractListing<T>) super.getComponent();
}
@Override
diff --git a/server/src/main/java/com/vaadin/ui/AbstractListing.java b/server/src/main/java/com/vaadin/ui/AbstractListing.java
index 3892e55662..40d3001ca6 100644
--- a/server/src/main/java/com/vaadin/ui/AbstractListing.java
+++ b/server/src/main/java/com/vaadin/ui/AbstractListing.java
@@ -32,13 +32,11 @@ import com.vaadin.server.data.DataSource;
*
* @param <T>
* the item data type
- * @param <SELECTIONMODEL>
- * the selection logic supported by this listing
*
* @since 8.0
*/
-public abstract class AbstractListing<T, SELECTIONMODEL extends SelectionModel<T>>
- extends AbstractComponent implements Listing<T, SELECTIONMODEL> {
+public abstract class AbstractListing<T> extends AbstractComponent
+ implements Listing<T> {
/**
* A helper base class for creating extensions for Listing components. This
@@ -57,7 +55,7 @@ public abstract class AbstractListing<T, SELECTIONMODEL extends SelectionModel<T
* @param listing
* the parent component to add to
*/
- public void extend(AbstractListing<T, ?> listing) {
+ public void extend(AbstractListing<T> listing) {
super.extend(listing);
listing.addDataGenerator(this);
}
@@ -82,8 +80,8 @@ public abstract class AbstractListing<T, SELECTIONMODEL extends SelectionModel<T
@Override
@SuppressWarnings("unchecked")
- public AbstractListing<T, ?> getParent() {
- return (AbstractListing<T, ?>) super.getParent();
+ public AbstractListing<T> getParent() {
+ return (AbstractListing<T>) super.getParent();
}
/**
@@ -100,8 +98,6 @@ public abstract class AbstractListing<T, SELECTIONMODEL extends SelectionModel<T
private final DataCommunicator<T> dataCommunicator;
- private SELECTIONMODEL selectionModel;
-
/**
* Creates a new {@code AbstractListing} with a default data communicator.
* <p>
@@ -146,29 +142,6 @@ public abstract class AbstractListing<T, SELECTIONMODEL extends SelectionModel<T
return getDataCommunicator().getDataSource();
}
- @Override
- public SELECTIONMODEL getSelectionModel() {
- assert selectionModel != null : "No selection model set by "
- + getClass().getName() + " constructor";
- return selectionModel;
- }
-
- /**
- * Sets the selection model for this listing.
- *
- * @param model
- * the selection model to use, not null
- */
- protected void setSelectionModel(SELECTIONMODEL model) {
- if (selectionModel != null) {
- throw new IllegalStateException(
- "A selection model can't be changed.");
- }
-
- Objects.requireNonNull(model, "selection model cannot be null");
- selectionModel = model;
- }
-
/**
* Adds the given data generator to this listing. If the generator was
* already added, does nothing.
diff --git a/server/src/main/java/com/vaadin/ui/AbstractMultiSelect.java b/server/src/main/java/com/vaadin/ui/AbstractMultiSelect.java
index 779cd959dd..fc6ce4f0a4 100644
--- a/server/src/main/java/com/vaadin/ui/AbstractMultiSelect.java
+++ b/server/src/main/java/com/vaadin/ui/AbstractMultiSelect.java
@@ -52,158 +52,16 @@ import elemental.json.JsonObject;
* @author Vaadin Ltd
* @since 8.0
*/
-public abstract class AbstractMultiSelect<T>
- extends AbstractListing<T, Multi<T>> implements HasValue<Set<T>> {
+public abstract class AbstractMultiSelect<T> extends AbstractListing<T>
+ implements MultiSelect<T> {
- /**
- * Simple implementation of multiselectmodel.
- */
- protected class SimpleMultiSelectModel implements SelectionModel.Multi<T> {
-
- private Set<T> selection = new LinkedHashSet<>();
-
- @Override
- public void select(T item) {
- // Not user originated
- select(item, false);
- }
-
- /**
- * Selects the given item. Depending on the implementation, may cause
- * other items to be deselected. If the item is already selected, does
- * nothing.
- *
- * @param item
- * the item to select, not null
- * @param userOriginated
- * {@code true} if this was used originated, {@code false} if
- * not
- */
- protected void select(T item, boolean userOriginated) {
- if (selection.contains(item)) {
- return;
- }
-
- updateSelection(set -> set.add(item), userOriginated);
- }
-
- @Override
- public void updateSelection(Set<T> addedItems, Set<T> removedItems) {
- updateSelection(addedItems, removedItems, false);
- }
-
- /**
- * Updates the selection by adding and removing the given items.
- *
- * @param addedItems
- * the items added to selection, not {@code} null
- * @param removedItems
- * the items removed from selection, not {@code} null
- * @param userOriginated
- * {@code true} if this was used originated, {@code false} if
- * not
- */
- protected void updateSelection(Set<T> addedItems, Set<T> removedItems,
- boolean userOriginated) {
- Objects.requireNonNull(addedItems);
- Objects.requireNonNull(removedItems);
-
- // if there are duplicates, some item is both added & removed, just
- // discard that and leave things as was before
- addedItems.removeIf(item -> removedItems.remove(item));
-
- if (selection.containsAll(addedItems)
- && Collections.disjoint(selection, removedItems)) {
- return;
- }
-
- updateSelection(set -> {
- // order of add / remove does not matter since no duplicates
- set.removeAll(removedItems);
- set.addAll(addedItems);
- }, userOriginated);
- }
-
- @Override
- public Set<T> getSelectedItems() {
- return Collections.unmodifiableSet(new LinkedHashSet<>(selection));
- }
-
- @Override
- public void deselect(T item) {
- // Not user originated
- deselect(item, false);
- }
-
- /**
- * Deselects the given item. If the item is not currently selected, does
- * nothing.
- *
- * @param item
- * the item to deselect, not null
- * @param userOriginated
- * {@code true} if this was used originated, {@code false} if
- * not
- */
- protected void deselect(T item, boolean userOriginated) {
- if (!selection.contains(item)) {
- return;
- }
-
- updateSelection(set -> set.remove(item), userOriginated);
- }
-
- /**
- * Removes the given items. Any item that is not currently selected, is
- * ignored. If none of the items are selected, does nothing.
- *
- * @param items
- * the items to deselect, not {@code null}
- * @param userOriginated
- * {@code true} if this was used originated, {@code false} if
- * not
- */
- protected void deselect(Set<T> items, boolean userOriginated) {
- Objects.requireNonNull(items);
- if (items.stream().noneMatch(i -> isSelected(i))) {
- return;
- }
-
- updateSelection(set -> set.removeAll(items), userOriginated);
- }
-
- @Override
- public void deselectAll() {
- if (selection.isEmpty()) {
- return;
- }
-
- updateSelection(Set::clear, false);
- }
-
- private void updateSelection(Consumer<Set<T>> handler,
- boolean userOriginated) {
- LinkedHashSet<T> oldSelection = new LinkedHashSet<>(selection);
- handler.accept(selection);
- LinkedHashSet<T> newSelection = new LinkedHashSet<>(selection);
-
- fireEvent(new MultiSelectionEvent<>(AbstractMultiSelect.this,
- oldSelection, userOriginated));
-
- getDataCommunicator().reset();
- }
-
- @Override
- public boolean isSelected(T item) {
- return selection.contains(item);
- }
- }
+ private Set<T> selection = new LinkedHashSet<>();
private class MultiSelectServerRpcImpl implements MultiSelectServerRpc {
@Override
public void updateSelection(Set<String> selectedItemKeys,
Set<String> deselectedItemKeys) {
- getSelectionModel().updateSelection(
+ AbstractMultiSelect.this.updateSelection(
getItemsForSelectionChange(selectedItemKeys),
getItemsForSelectionChange(deselectedItemKeys), true);
}
@@ -223,10 +81,6 @@ public abstract class AbstractMultiSelect<T>
return Optional.of(item);
}
- private SimpleMultiSelectModel getSelectionModel() {
- return (SimpleMultiSelectModel) AbstractMultiSelect.this
- .getSelectionModel();
- }
}
private class MultiSelectDataGenerator implements DataGenerator<T> {
@@ -250,7 +104,7 @@ public abstract class AbstractMultiSelect<T>
true);
}
- if (getSelectionModel().isSelected(data)) {
+ if (isSelected(data)) {
jsonObject.put(ListingJsonConstants.JSONKEY_ITEM_SELECTED,
true);
}
@@ -287,8 +141,6 @@ public abstract class AbstractMultiSelect<T>
* Creates a new multi select with an empty data source.
*/
protected AbstractMultiSelect() {
- setSelectionModel(new SimpleMultiSelectModel());
-
registerRpc(new MultiSelectServerRpcImpl());
// #FIXME it should be the responsibility of the SelectionModel
@@ -304,6 +156,7 @@ public abstract class AbstractMultiSelect<T>
* the value change listener, not {@code null}
* @return a registration for the listener
*/
+ @Override
public Registration addSelectionListener(
MultiSelectionListener<T> listener) {
addListener(MultiSelectionEvent.class, listener,
@@ -376,8 +229,7 @@ public abstract class AbstractMultiSelect<T>
Set<T> copy = value.stream().map(Objects::requireNonNull)
.collect(Collectors.toCollection(LinkedHashSet::new));
- getSelectionModel().updateSelection(copy,
- new LinkedHashSet<>(getSelectionModel().getSelectedItems()));
+ updateSelection(copy, new LinkedHashSet<>(getSelectedItems()));
}
@Override
@@ -502,4 +354,122 @@ public abstract class AbstractMultiSelect<T>
public boolean isReadOnly() {
return super.isReadOnly();
}
+
+ @Override
+ public void updateSelection(Set<T> addedItems, Set<T> removedItems) {
+ updateSelection(addedItems, removedItems, false);
+ }
+
+ /**
+ * Updates the selection by adding and removing the given items.
+ *
+ * @param addedItems
+ * the items added to selection, not {@code} null
+ * @param removedItems
+ * the items removed from selection, not {@code} null
+ * @param userOriginated
+ * {@code true} if this was used originated, {@code false} if not
+ */
+ protected void updateSelection(Set<T> addedItems, Set<T> removedItems,
+ boolean userOriginated) {
+ Objects.requireNonNull(addedItems);
+ Objects.requireNonNull(removedItems);
+
+ // if there are duplicates, some item is both added & removed, just
+ // discard that and leave things as was before
+ addedItems.removeIf(item -> removedItems.remove(item));
+
+ if (selection.containsAll(addedItems)
+ && Collections.disjoint(selection, removedItems)) {
+ return;
+ }
+
+ updateSelection(set -> {
+ // order of add / remove does not matter since no duplicates
+ set.removeAll(removedItems);
+ set.addAll(addedItems);
+ }, userOriginated);
+ }
+
+ @Override
+ public Set<T> getSelectedItems() {
+ return Collections.unmodifiableSet(new LinkedHashSet<>(selection));
+ }
+
+ @Override
+ public void deselectAll() {
+ if (selection.isEmpty()) {
+ return;
+ }
+
+ updateSelection(Set::clear, false);
+ }
+
+ @Override
+ public boolean isSelected(T item) {
+ return selection.contains(item);
+ }
+
+ /**
+ * Deselects the given item. If the item is not currently selected, does
+ * nothing.
+ *
+ * @param item
+ * the item to deselect, not null
+ * @param userOriginated
+ * {@code true} if this was used originated, {@code false} if not
+ */
+ protected void deselect(T item, boolean userOriginated) {
+ if (!selection.contains(item)) {
+ return;
+ }
+
+ updateSelection(set -> set.remove(item), userOriginated);
+ }
+
+ /**
+ * Removes the given items. Any item that is not currently selected, is
+ * ignored. If none of the items are selected, does nothing.
+ *
+ * @param items
+ * the items to deselect, not {@code null}
+ * @param userOriginated
+ * {@code true} if this was used originated, {@code false} if not
+ */
+ protected void deselect(Set<T> items, boolean userOriginated) {
+ Objects.requireNonNull(items);
+ if (items.stream().noneMatch(i -> isSelected(i))) {
+ return;
+ }
+
+ updateSelection(set -> set.removeAll(items), userOriginated);
+ }
+
+ /**
+ * Selects the given item. Depending on the implementation, may cause other
+ * items to be deselected. If the item is already selected, does nothing.
+ *
+ * @param item
+ * the item to select, not null
+ * @param userOriginated
+ * {@code true} if this was used originated, {@code false} if not
+ */
+ protected void select(T item, boolean userOriginated) {
+ if (selection.contains(item)) {
+ return;
+ }
+
+ updateSelection(set -> set.add(item), userOriginated);
+ }
+
+ private void updateSelection(Consumer<Set<T>> handler,
+ boolean userOriginated) {
+ LinkedHashSet<T> oldSelection = new LinkedHashSet<>(selection);
+ handler.accept(selection);
+
+ fireEvent(new MultiSelectionEvent<>(AbstractMultiSelect.this,
+ oldSelection, userOriginated));
+
+ getDataCommunicator().reset();
+ }
}
diff --git a/server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java b/server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java
index cb72d52444..7125139d8a 100644
--- a/server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java
+++ b/server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java
@@ -43,189 +43,9 @@ import com.vaadin.util.ReflectTools;
*
* @since 8.0
*/
-public abstract class AbstractSingleSelect<T> extends
- AbstractListing<T, AbstractSingleSelect<T>.AbstractSingleSelection>
+public abstract class AbstractSingleSelect<T> extends AbstractListing<T>
implements SingleSelect<T> {
- /**
- * A base class for single selection model implementations. Listens to
- * {@code SelectionServerRpc} invocations to track selection requests by the
- * client. Maintaining the selection state and communicating it from the
- * server to the client is the responsibility of the implementing class.
- */
- public abstract class AbstractSingleSelection
- implements SelectionModel.Single<T> {
-
- /**
- * Creates a new {@code SimpleSingleSelection} instance.
- */
- public AbstractSingleSelection() {
- registerRpc(new SelectionServerRpc() {
-
- @Override
- public void select(String key) {
- setSelectedFromClient(key);
- }
-
- @Override
- public void deselect(String key) {
- if (isKeySelected(key)) {
- setSelectedFromClient(null);
- }
- }
- });
- }
-
- @Override
- public void deselect(T item) {
- Objects.requireNonNull(item, "deselected item cannot be null");
- if (isSelected(item)) {
- setSelectedFromServer(null);
- }
- }
-
- @Override
- public void select(T item) {
- Objects.requireNonNull(item, "selected item cannot be null");
- setSelectedFromServer(item);
- }
-
- /**
- * Returns the communication key of the selected item or {@code null} if
- * no item is selected.
- *
- * @return the key of the selected item if any, {@code null} otherwise.
- */
- protected abstract String getSelectedKey();
-
- /**
- * Sets the selected item based on the given communication key. If the
- * key is {@code null}, clears the current selection if any.
- *
- * @param key
- * the key of the selected item or {@code null} to clear
- * selection
- */
- protected abstract void doSetSelectedKey(String key);
-
- /**
- * Sets the selection based on a client request. Does nothing if the
- * select component is {@linkplain Component#isReadOnly()} or if the
- * selection would not change. Otherwise updates the selection and fires
- * a selection change event with {@code isUserOriginated == true}.
- *
- * @param key
- * the key of the item to select or {@code null} to clear
- * selection
- */
- protected void setSelectedFromClient(String key) {
- if (isReadOnly()) {
- return;
- }
- if (isKeySelected(key)) {
- return;
- }
-
- doSetSelectedKey(key);
- fireEvent(new SingleSelectionChangeEvent<>(
- AbstractSingleSelect.this, true));
- }
-
- /**
- * Sets the selection based on server API call. Does nothing if the
- * selection would not change; otherwise updates the selection and fires
- * a selection change event with {@code isUserOriginated == false}.
- *
- * @param item
- * the item to select or {@code null} to clear selection
- */
- protected void setSelectedFromServer(T item) {
- // TODO creates a key if item not in data source
- String key = itemToKey(item);
-
- if (isKeySelected(key) || isSelected(item)) {
- return;
- }
-
- doSetSelectedKey(key);
- fireEvent(new SingleSelectionChangeEvent<>(
- AbstractSingleSelect.this, false));
- }
-
- /**
- * Returns whether the given key maps to the currently selected item.
- *
- * @param key
- * the key to test or {@code null} to test whether nothing is
- * selected
- * @return {@code true} if the key equals the key of the currently
- * selected item (or {@code null} if no selection),
- * {@code false} otherwise.
- */
- protected boolean isKeySelected(String key) {
- return Objects.equals(key, getSelectedKey());
- }
-
- /**
- * Returns the communication key assigned to the given item.
- *
- * @param item
- * the item whose key to return
- * @return the assigned key
- */
- protected String itemToKey(T item) {
- if (item == null) {
- return null;
- } else {
- // TODO creates a key if item not in data source
- return getDataCommunicator().getKeyMapper().key(item);
- }
- }
-
- /**
- * Returns the item that the given key is assigned to, or {@code null}
- * if there is no such item.
- *
- * @param key
- * the key whose item to return
- * @return the associated item if any, {@code null} otherwise.
- */
- protected T keyToItem(String key) {
- return getDataCommunicator().getKeyMapper().get(key);
- }
- }
-
- /**
- * A simple single selection model using the {@code AbstractSingleSelect}
- * RPC and state to communicate with the client. Has no client-side
- * counterpart; the listing connector is expected to handle selection.
- * Client-to-server selection is passed via {@link SelectionServerRpc} and
- * server-to-client via {@link AbstractSingleSelectState#selectedItemKey}.
- */
- protected class SimpleSingleSelection extends AbstractSingleSelection {
-
- /**
- * Creates a new {@code SimpleSingleSelection}.
- */
- public SimpleSingleSelection() {
- }
-
- @Override
- public Optional<T> getSelectedItem() {
- return Optional.ofNullable(keyToItem(getSelectedKey()));
- }
-
- @Override
- protected String getSelectedKey() {
- return getState(false).selectedItemKey;
- }
-
- @Override
- protected void doSetSelectedKey(String key) {
- getState().selectedItemKey = key;
- }
- }
-
@Deprecated
private static final Method SELECTION_CHANGE_METHOD = ReflectTools
.findMethod(SingleSelectionListener.class, "accept",
@@ -240,6 +60,7 @@ public abstract class AbstractSingleSelect<T> extends
* {@link AbstractSingleSelect.AbstractSingleSelection} .
*/
protected AbstractSingleSelect() {
+ init();
}
/**
@@ -260,6 +81,7 @@ public abstract class AbstractSingleSelect<T> extends
*/
protected AbstractSingleSelect(DataCommunicator<T> dataCommunicator) {
super(dataCommunicator);
+ init();
}
/**
@@ -285,7 +107,7 @@ public abstract class AbstractSingleSelect<T> extends
* otherwise
*/
public Optional<T> getSelectedItem() {
- return getSelectionModel().getSelectedItem();
+ return Optional.ofNullable(keyToItem(getSelectedKey()));
}
/**
@@ -296,7 +118,7 @@ public abstract class AbstractSingleSelect<T> extends
* the item to select or {@code null} to clear selection
*/
public void setSelectedItem(T item) {
- getSelectionModel().setSelectedItem(item);
+ setSelectedFromServer(item);
}
/**
@@ -369,4 +191,152 @@ public abstract class AbstractSingleSelect<T> extends
public boolean isReadOnly() {
return super.isReadOnly();
}
+
+ public void deselect(T item) {
+ Objects.requireNonNull(item, "deselected item cannot be null");
+ if (isSelected(item)) {
+ setSelectedFromServer(null);
+ }
+ }
+
+ public void select(T item) {
+ Objects.requireNonNull(item, "selected item cannot be null");
+ setSelectedFromServer(item);
+ }
+
+ /**
+ * Returns the communication key of the selected item or {@code null} if no
+ * item is selected.
+ *
+ * @return the key of the selected item if any, {@code null} otherwise.
+ */
+ protected String getSelectedKey() {
+ return getState(false).selectedItemKey;
+ }
+
+ /**
+ * Sets the selected item based on the given communication key. If the key
+ * is {@code null}, clears the current selection if any.
+ *
+ * @param key
+ * the key of the selected item or {@code null} to clear
+ * selection
+ */
+ protected void doSetSelectedKey(String key) {
+ getState().selectedItemKey = key;
+ }
+
+ /**
+ * Sets the selection based on a client request. Does nothing if the select
+ * component is {@linkplain Component#isReadOnly()} or if the selection
+ * would not change. Otherwise updates the selection and fires a selection
+ * change event with {@code isUserOriginated == true}.
+ *
+ * @param key
+ * the key of the item to select or {@code null} to clear
+ * selection
+ */
+ protected void setSelectedFromClient(String key) {
+ if (isReadOnly()) {
+ return;
+ }
+ if (isKeySelected(key)) {
+ return;
+ }
+
+ doSetSelectedKey(key);
+ fireEvent(new SingleSelectionChangeEvent<>(AbstractSingleSelect.this,
+ true));
+ }
+
+ /**
+ * Sets the selection based on server API call. Does nothing if the
+ * selection would not change; otherwise updates the selection and fires a
+ * selection change event with {@code isUserOriginated == false}.
+ *
+ * @param item
+ * the item to select or {@code null} to clear selection
+ */
+ protected void setSelectedFromServer(T item) {
+ // TODO creates a key if item not in data source
+ String key = itemToKey(item);
+
+ if (isKeySelected(key) || isSelected(item)) {
+ return;
+ }
+
+ doSetSelectedKey(key);
+ fireEvent(new SingleSelectionChangeEvent<>(AbstractSingleSelect.this,
+ false));
+ }
+
+ /**
+ * Returns whether the given key maps to the currently selected item.
+ *
+ * @param key
+ * the key to test or {@code null} to test whether nothing is
+ * selected
+ * @return {@code true} if the key equals the key of the currently selected
+ * item (or {@code null} if no selection), {@code false} otherwise.
+ */
+ protected boolean isKeySelected(String key) {
+ return Objects.equals(key, getSelectedKey());
+ }
+
+ /**
+ * Returns the communication key assigned to the given item.
+ *
+ * @param item
+ * the item whose key to return
+ * @return the assigned key
+ */
+ protected String itemToKey(T item) {
+ if (item == null) {
+ return null;
+ } else {
+ // TODO creates a key if item not in data source
+ return getDataCommunicator().getKeyMapper().key(item);
+ }
+ }
+
+ /**
+ * Returns the item that the given key is assigned to, or {@code null} if
+ * there is no such item.
+ *
+ * @param key
+ * the key whose item to return
+ * @return the associated item if any, {@code null} otherwise.
+ */
+ protected T keyToItem(String key) {
+ return getDataCommunicator().getKeyMapper().get(key);
+ }
+
+ /**
+ * Returns whether the given item is currently selected.
+ *
+ * @param item
+ * the item to check, not null
+ * @return {@code true} if the item is selected, {@code false} otherwise
+ */
+ public boolean isSelected(T item) {
+ return Objects.equals(getValue(), item);
+ }
+
+ private void init() {
+ registerRpc(new SelectionServerRpc() {
+
+ @Override
+ public void select(String key) {
+ setSelectedFromClient(key);
+ }
+
+ @Override
+ public void deselect(String key) {
+ if (isKeySelected(key)) {
+ setSelectedFromClient(null);
+ }
+ }
+ });
+ }
+
}
diff --git a/server/src/main/java/com/vaadin/ui/ComboBox.java b/server/src/main/java/com/vaadin/ui/ComboBox.java
index 8ceaec125c..097ae30bc7 100644
--- a/server/src/main/java/com/vaadin/ui/ComboBox.java
+++ b/server/src/main/java/com/vaadin/ui/ComboBox.java
@@ -56,24 +56,6 @@ public class ComboBox<T> extends AbstractSingleSelect<T> implements HasValue<T>,
FieldEvents.BlurNotifier, FieldEvents.FocusNotifier {
/**
- * Custom single selection model for ComboBox.
- */
- protected class ComboBoxSelectionModel extends SimpleSingleSelection {
- @Override
- protected void doSetSelectedKey(String key) {
- super.doSetSelectedKey(key);
-
- String selectedCaption = null;
- T value = getDataCommunicator().getKeyMapper().get(key);
- if (value != null) {
- selectedCaption = getItemCaptionGenerator().apply(value);
- }
- getState().selectedItemCaption = selectedCaption;
- }
-
- }
-
- /**
* Handler that adds a new item based on user input when the new items
* allowed mode is active.
*/
@@ -158,7 +140,6 @@ public class ComboBox<T> extends AbstractSingleSelect<T> implements HasValue<T>,
};
}
});
- setSelectionModel(new ComboBoxSelectionModel());
init();
}
@@ -540,24 +521,6 @@ public class ComboBox<T> extends AbstractSingleSelect<T> implements HasValue<T>,
this.filter = filter;
}
- /**
- * Sets the value of this object. If the new value is not equal to
- * {@code getValue()}, fires a {@link ValueChangeEvent}.
- *
- * @param value
- * the new value, may be {@code null}
- */
- @Override
- public void setValue(T value) {
- getSelectionModel().setSelectedFromServer(value);
-
- }
-
- @Override
- public T getValue() {
- return getSelectionModel().getSelectedItem().orElse(null);
- }
-
@Override
public Registration addValueChangeListener(
HasValue.ValueChangeListener<T> listener) {
@@ -577,4 +540,16 @@ public class ComboBox<T> extends AbstractSingleSelect<T> implements HasValue<T>,
return (ComboBoxState) super.getState(markAsDirty);
}
+ @Override
+ protected void doSetSelectedKey(String key) {
+ super.doSetSelectedKey(key);
+
+ String selectedCaption = null;
+ T value = getDataCommunicator().getKeyMapper().get(key);
+ if (value != null) {
+ selectedCaption = getItemCaptionGenerator().apply(value);
+ }
+ getState().selectedItemCaption = selectedCaption;
+ }
+
}
diff --git a/server/src/main/java/com/vaadin/ui/Grid.java b/server/src/main/java/com/vaadin/ui/Grid.java
index bf50d6a53d..b738b71323 100644
--- a/server/src/main/java/com/vaadin/ui/Grid.java
+++ b/server/src/main/java/com/vaadin/ui/Grid.java
@@ -37,9 +37,11 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import com.vaadin.data.SelectionModel.Single;
import com.vaadin.event.ConnectorEvent;
import com.vaadin.event.ContextClickEvent;
import com.vaadin.event.EventListener;
+import com.vaadin.event.selection.SingleSelectionChangeEvent;
import com.vaadin.server.EncodeResult;
import com.vaadin.server.JsonCodec;
import com.vaadin.server.SerializableComparator;
@@ -48,6 +50,7 @@ import com.vaadin.server.data.SortOrder;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.Registration;
import com.vaadin.shared.data.DataCommunicatorConstants;
+import com.vaadin.shared.data.selection.SelectionServerRpc;
import com.vaadin.shared.data.sort.SortDirection;
import com.vaadin.shared.ui.grid.ColumnState;
import com.vaadin.shared.ui.grid.GridConstants;
@@ -488,7 +491,7 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents {
extends AbstractListingExtension<T> {
@Override
- public void extend(AbstractListing<T, ?> grid) {
+ public void extend(AbstractListing<T> grid) {
if (!(grid instanceof Grid)) {
throw new IllegalArgumentException(
getClass().getSimpleName() + " can only extend Grid");
@@ -1485,7 +1488,7 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents {
}
}
- private final class SingleSelection extends AbstractSingleSelection {
+ private final class SingleSelection implements Single<T> {
private T selectedItem = null;
SingleSelection() {
@@ -1494,6 +1497,20 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents {
json.put(DataCommunicatorConstants.SELECTED, true);
}
});
+ registerRpc(new SelectionServerRpc() {
+
+ @Override
+ public void select(String key) {
+ setSelectedFromClient(key);
+ }
+
+ @Override
+ public void deselect(String key) {
+ if (isKeySelected(key)) {
+ setSelectedFromClient(null);
+ }
+ }
+ });
}
@Override
@@ -1502,16 +1519,51 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents {
}
@Override
+ public void deselect(T item) {
+ Objects.requireNonNull(item, "deselected item cannot be null");
+ if (isSelected(item)) {
+ setSelectedFromServer(null);
+ }
+ }
+
+ @Override
+ public void select(T item) {
+ Objects.requireNonNull(item, "selected item cannot be null");
+ setSelectedFromServer(item);
+ }
+
+ /**
+ * Returns whether the given key maps to the currently selected item.
+ *
+ * @param key
+ * the key to test or {@code null} to test whether nothing is
+ * selected
+ * @return {@code true} if the key equals the key of the currently
+ * selected item (or {@code null} if no selection),
+ * {@code false} otherwise.
+ */
protected boolean isKeySelected(String key) {
return Objects.equals(key, getSelectedKey());
}
- @Override
+ /**
+ * Returns the communication key of the selected item or {@code null} if
+ * no item is selected.
+ *
+ * @return the key of the selected item if any, {@code null} otherwise.
+ */
protected String getSelectedKey() {
return itemToKey(selectedItem);
}
- @Override
+ /**
+ * Sets the selected item based on the given communication key. If the
+ * key is {@code null}, clears the current selection if any.
+ *
+ * @param key
+ * the key of the selected item or {@code null} to clear
+ * selection
+ */
protected void doSetSelectedKey(String key) {
if (selectedItem != null) {
getDataCommunicator().refresh(selectedItem);
@@ -1521,6 +1573,76 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents {
getDataCommunicator().refresh(selectedItem);
}
}
+
+ /**
+ * Sets the selection based on a client request. Does nothing if the
+ * select component is {@linkplain Component#isReadOnly()} or if the
+ * selection would not change. Otherwise updates the selection and fires
+ * a selection change event with {@code isUserOriginated == true}.
+ *
+ * @param key
+ * the key of the item to select or {@code null} to clear
+ * selection
+ */
+ protected void setSelectedFromClient(String key) {
+ if (isReadOnly()) {
+ return;
+ }
+ if (isKeySelected(key)) {
+ return;
+ }
+
+ doSetSelectedKey(key);
+ fireEvent(new SingleSelectionChangeEvent<>(Grid.this, true));
+ }
+
+ /**
+ * Sets the selection based on server API call. Does nothing if the
+ * selection would not change; otherwise updates the selection and fires
+ * a selection change event with {@code isUserOriginated == false}.
+ *
+ * @param item
+ * the item to select or {@code null} to clear selection
+ */
+ protected void setSelectedFromServer(T item) {
+ // TODO creates a key if item not in data source
+ String key = itemToKey(item);
+
+ if (isKeySelected(key) || isSelected(item)) {
+ return;
+ }
+
+ doSetSelectedKey(key);
+ fireEvent(new SingleSelectionChangeEvent<>(Grid.this, false));
+ }
+
+ /**
+ * Returns the communication key assigned to the given item.
+ *
+ * @param item
+ * the item whose key to return
+ * @return the assigned key
+ */
+ protected String itemToKey(T item) {
+ if (item == null) {
+ return null;
+ } else {
+ // TODO creates a key if item not in data source
+ return getDataCommunicator().getKeyMapper().key(item);
+ }
+ }
+
+ /**
+ * Returns the item that the given key is assigned to, or {@code null}
+ * if there is no such item.
+ *
+ * @param key
+ * the key whose item to return
+ * @return the associated item if any, {@code null} otherwise.
+ */
+ protected T keyToItem(String key) {
+ return getDataCommunicator().getKeyMapper().get(key);
+ }
}
/**
@@ -1713,6 +1835,8 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents {
private int counter = 0;
+ private Single<T> selectionModel;
+
/**
* Constructor for the {@link Grid} component.
*/
@@ -2561,6 +2685,38 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents {
fireColumnReorderEvent(false);
}
+ /**
+ * Returns the selection model for this listing.
+ *
+ * @return the selection model, not null
+ */
+ public Single<T> getSelectionModel() {
+ assert selectionModel != null : "No selection model set by "
+ + getClass().getName() + " constructor";
+ return selectionModel;
+ }
+
+ @Override
+ public Optional<T> getSelectedItem() {
+ return getSelectionModel().getSelectedItem();
+ }
+
+ /**
+ * Sets the selection model for this listing.
+ *
+ * @param model
+ * the selection model to use, not null
+ */
+ protected void setSelectionModel(Single<T> model) {
+ if (selectionModel != null) {
+ throw new IllegalStateException(
+ "A selection model can't be changed.");
+ }
+
+ Objects.requireNonNull(model, "selection model cannot be null");
+ selectionModel = model;
+ }
+
@Override
protected GridState getState() {
return getState(true);
diff --git a/server/src/main/java/com/vaadin/ui/MultiSelect.java b/server/src/main/java/com/vaadin/ui/MultiSelect.java
new file mode 100644
index 0000000000..a3677d6d4e
--- /dev/null
+++ b/server/src/main/java/com/vaadin/ui/MultiSelect.java
@@ -0,0 +1,139 @@
+/*
+ * 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.ui;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import com.vaadin.data.HasValue;
+import com.vaadin.event.selection.MultiSelectionListener;
+import com.vaadin.shared.Registration;
+
+/**
+ * Multi selection component which allows to select and deselect multiple items.
+ *
+ * @author Vaadin Ltd
+ *
+ * @param <T>
+ * the type of the items to select
+ *
+ * @since 8.0
+ *
+ */
+public interface MultiSelect<T> extends HasValue<Set<T>>, Serializable {
+
+ /**
+ * Adds the given items to the set of currently selected items.
+ * <p>
+ * By default this does not clear any previous selection. To do that, use
+ * {@link #deselectAll()}.
+ * <p>
+ * If the all the items were already selected, this is a NO-OP.
+ * <p>
+ * This is a short-hand for {@link #updateSelection(Set, Set)} with nothing
+ * to deselect.
+ *
+ * @param items
+ * to add to selection, not {@code null}
+ */
+ public default void select(T... items) {
+ Objects.requireNonNull(items);
+ Stream.of(items).forEach(Objects::requireNonNull);
+
+ updateSelection(new LinkedHashSet<>(Arrays.asList(items)),
+ Collections.emptySet());
+ }
+
+ /**
+ * Removes the given items from the set of currently selected items.
+ * <p>
+ * If the none of the items were selected, this is a NO-OP.
+ * <p>
+ * This is a short-hand for {@link #updateSelection(Set, Set)} with nothing
+ * to select.
+ *
+ * @param items
+ * to remove from selection, not {@code null}
+ */
+ public default void deselect(T... items) {
+ Objects.requireNonNull(items);
+ Stream.of(items).forEach(Objects::requireNonNull);
+
+ updateSelection(Collections.emptySet(),
+ new LinkedHashSet<>(Arrays.asList(items)));
+ }
+
+ /**
+ * Updates the selection by adding and removing the given items from it.
+ * <p>
+ * If all the added items were already selected and the removed items were
+ * not selected, this is a NO-OP.
+ * <p>
+ * Duplicate items (in both add & remove sets) are ignored.
+ *
+ * @param addedItems
+ * the items to add, not {@code null}
+ * @param removedItems
+ * the items to remove, not {@code null}
+ */
+ public void updateSelection(Set<T> addedItems, Set<T> removedItems);
+
+ /**
+ * Returns an immutable set of the currently selected items. It is safe to
+ * invoke other {@code SelectionModel} methods while iterating over the set.
+ * <p>
+ * <em>Implementation note:</em> the iteration order of the items in the
+ * returned set should be well-defined and documented by the implementing
+ * class.
+ *
+ * @return the items in the current selection, not null
+ */
+ public Set<T> getSelectedItems();
+
+ /**
+ * Deselects all currently selected items.
+ */
+ public default void deselectAll() {
+ getSelectedItems().forEach(this::deselect);
+ }
+
+ /**
+ * Returns whether the given item is currently selected.
+ *
+ * @param item
+ * the item to check, not null
+ * @return {@code true} if the item is selected, {@code false} otherwise
+ */
+ public default boolean isSelected(T item) {
+ return getSelectedItems().contains(item);
+ }
+
+ /**
+ * Adds a selection listener that will be called when the selection is
+ * changed either by the user or programmatically.
+ *
+ * @param listener
+ * the value change listener, not {@code null}
+ * @return a registration for the listener
+ */
+ public Registration addSelectionListener(
+ MultiSelectionListener<T> listener);
+}
diff --git a/server/src/main/java/com/vaadin/ui/NativeSelect.java b/server/src/main/java/com/vaadin/ui/NativeSelect.java
index bb3ae41df4..a1ec0dca40 100644
--- a/server/src/main/java/com/vaadin/ui/NativeSelect.java
+++ b/server/src/main/java/com/vaadin/ui/NativeSelect.java
@@ -52,8 +52,6 @@ public class NativeSelect<T> extends AbstractSingleSelect<T>
registerRpc(new FocusAndBlurServerRpcDecorator(this, this::fireEvent));
addDataGenerator((item, json) -> json
.put(DataCommunicatorConstants.DATA, String.valueOf(item)));
-
- setSelectionModel(new SimpleSingleSelection());
}
/**
diff --git a/server/src/main/java/com/vaadin/ui/RadioButtonGroup.java b/server/src/main/java/com/vaadin/ui/RadioButtonGroup.java
index 6f1191e8d4..4c5b814f22 100644
--- a/server/src/main/java/com/vaadin/ui/RadioButtonGroup.java
+++ b/server/src/main/java/com/vaadin/ui/RadioButtonGroup.java
@@ -103,7 +103,6 @@ public class RadioButtonGroup<T> extends AbstractSingleSelect<T>
*/
public RadioButtonGroup() {
registerRpc(new FocusAndBlurServerRpcDecorator(this, this::fireEvent));
- setSelectionModel(new SimpleSingleSelection());
addDataGenerator(new DataGenerator<T>() {
@Override
@@ -127,7 +126,7 @@ public class RadioButtonGroup<T> extends AbstractSingleSelect<T>
true);
}
- if (getSelectionModel().isSelected(data)) {
+ if (isSelected(data)) {
jsonObject.put(ListingJsonConstants.JSONKEY_ITEM_SELECTED,
true);
}
diff --git a/server/src/test/java/com/vaadin/data/BinderMultiSelectTest.java b/server/src/test/java/com/vaadin/data/BinderMultiSelectTest.java
index f8a4313b09..c4725471da 100644
--- a/server/src/test/java/com/vaadin/data/BinderMultiSelectTest.java
+++ b/server/src/test/java/com/vaadin/data/BinderMultiSelectTest.java
@@ -157,7 +157,7 @@ public class BinderMultiSelectTest
converterBinder.readBean(new AtomicReference<>("TWO"));
assertEquals(Collections.singleton(TestEnum.TWO),
- select.getSelectionModel().getSelectedItems());
+ select.getSelectedItems());
}
@Test
diff --git a/server/src/test/java/com/vaadin/tests/components/grid/GridSelectionTest.java b/server/src/test/java/com/vaadin/tests/components/grid/GridSelectionTest.java
index 0522e26ac9..572413bb99 100644
--- a/server/src/test/java/com/vaadin/tests/components/grid/GridSelectionTest.java
+++ b/server/src/test/java/com/vaadin/tests/components/grid/GridSelectionTest.java
@@ -1,5 +1,7 @@
package com.vaadin.tests.components.grid;
+import java.util.Optional;
+
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -18,17 +20,17 @@ public class GridSelectionTest {
@Test
public void testGridWithSingleSelection() {
- Assert.assertFalse(grid.isSelected("Foo"));
- grid.select("Foo");
- Assert.assertTrue(grid.isSelected("Foo"));
- Assert.assertEquals(1, grid.getSelectedItems().size());
- Assert.assertEquals("Foo", grid.getSelectedItems().iterator().next());
- grid.select("Bar");
- Assert.assertFalse(grid.isSelected("Foo"));
- Assert.assertTrue(grid.isSelected("Bar"));
- grid.deselect("Bar");
- Assert.assertFalse(grid.isSelected("Bar"));
- Assert.assertEquals(0, grid.getSelectedItems().size());
+ Assert.assertFalse(grid.getSelectionModel().isSelected("Foo"));
+ grid.getSelectionModel().select("Foo");
+ Assert.assertTrue(grid.getSelectionModel().isSelected("Foo"));
+ Assert.assertEquals(Optional.of("Foo"), grid.getSelectedItem());
+ grid.getSelectionModel().select("Bar");
+ Assert.assertFalse(grid.getSelectionModel().isSelected("Foo"));
+ Assert.assertTrue(grid.getSelectionModel().isSelected("Bar"));
+ grid.getSelectionModel().deselect("Bar");
+ Assert.assertFalse(grid.getSelectionModel().isSelected("Bar"));
+ Assert.assertFalse(
+ grid.getSelectionModel().getSelectedItem().isPresent());
}
}
diff --git a/server/src/test/java/com/vaadin/ui/AbstractListingTest.java b/server/src/test/java/com/vaadin/ui/AbstractListingTest.java
index 585dce1f5e..494fc2e1c5 100644
--- a/server/src/test/java/com/vaadin/ui/AbstractListingTest.java
+++ b/server/src/test/java/com/vaadin/ui/AbstractListingTest.java
@@ -22,10 +22,6 @@ public class AbstractListingTest {
private final class TestListing extends AbstractSingleSelect<String> {
- protected TestListing() {
- setSelectionModel(new SimpleSingleSelection());
- }
-
/**
* Used to execute data generation
*/
diff --git a/server/src/test/java/com/vaadin/ui/AbstractMultiSelectTest.java b/server/src/test/java/com/vaadin/ui/AbstractMultiSelectTest.java
index 6d748f076a..92c288fc34 100644
--- a/server/src/test/java/com/vaadin/ui/AbstractMultiSelectTest.java
+++ b/server/src/test/java/com/vaadin/ui/AbstractMultiSelectTest.java
@@ -37,7 +37,6 @@ import org.junit.runners.Parameterized.Parameters;
import org.mockito.Mockito;
import com.vaadin.data.HasValue.ValueChangeEvent;
-import com.vaadin.data.SelectionModel.Multi;
import com.vaadin.event.selection.MultiSelectionEvent;
import com.vaadin.event.selection.MultiSelectionListener;
import com.vaadin.server.data.DataSource;
@@ -56,18 +55,16 @@ public class AbstractMultiSelectTest {
@Parameter
public AbstractMultiSelect<String> selectToTest;
- private Multi<String> selectionModel;
private MultiSelectServerRpc rpc;
private Registration registration;
@Before
public void setUp() {
- selectToTest.getSelectionModel().deselectAll();
+ selectToTest.deselectAll();
// Intentional deviation from upcoming selection order
selectToTest.setDataSource(
DataSource.create("3", "2", "1", "5", "8", "7", "4", "6"));
- selectionModel = selectToTest.getSelectionModel();
rpc = ComponentTest.getRpcProxy(selectToTest,
MultiSelectServerRpc.class);
}
@@ -82,28 +79,28 @@ public class AbstractMultiSelectTest {
@Test
public void stableSelectionOrder() {
- selectionModel.select("1");
- selectionModel.select("2");
- selectionModel.select("3");
+ selectToTest.select("1");
+ selectToTest.select("2");
+ selectToTest.select("3");
- assertSelectionOrder(selectionModel, "1", "2", "3");
+ assertSelectionOrder("1", "2", "3");
- selectionModel.deselect("1");
- assertSelectionOrder(selectionModel, "2", "3");
+ selectToTest.deselect("1");
+ assertSelectionOrder("2", "3");
- selectionModel.select("1");
- assertSelectionOrder(selectionModel, "2", "3", "1");
+ selectToTest.select("1");
+ assertSelectionOrder("2", "3", "1");
- selectionModel.selectItems("7", "8", "4");
- assertSelectionOrder(selectionModel, "2", "3", "1", "7", "8", "4");
+ selectToTest.select("7", "8", "4");
+ assertSelectionOrder("2", "3", "1", "7", "8", "4");
- selectionModel.deselectItems("2", "1", "4", "5");
- assertSelectionOrder(selectionModel, "3", "7", "8");
+ selectToTest.deselect("2", "1", "4", "5");
+ assertSelectionOrder("3", "7", "8");
- selectionModel.updateSelection(
+ selectToTest.updateSelection(
new LinkedHashSet<>(Arrays.asList("5", "2")),
new LinkedHashSet<>(Arrays.asList("3", "8")));
- assertSelectionOrder(selectionModel, "7", "5", "2");
+ assertSelectionOrder("7", "5", "2");
}
@Test
@@ -120,27 +117,27 @@ public class AbstractMultiSelectTest {
selectToTest.select("2");
selectToTest.deselect("2");
- selectToTest.getSelectionModel().deselectAll();
+ selectToTest.deselectAll();
- selectToTest.getSelectionModel().selectItems("2", "3", "4");
- selectToTest.getSelectionModel().deselectItems("1", "4");
+ selectToTest.select("2", "3", "4");
+ selectToTest.deselect("1", "4");
Assert.assertEquals(6, listenerCount.get());
// select partly selected
- selectToTest.getSelectionModel().selectItems("2", "3", "4");
+ selectToTest.select("2", "3", "4");
Assert.assertEquals(7, listenerCount.get());
// select completely selected
- selectToTest.getSelectionModel().selectItems("2", "3", "4");
+ selectToTest.select("2", "3", "4");
Assert.assertEquals(7, listenerCount.get());
// deselect partly not selected
- selectToTest.getSelectionModel().selectItems("1", "4");
+ selectToTest.select("1", "4");
Assert.assertEquals(8, listenerCount.get());
// deselect completely not selected
- selectToTest.getSelectionModel().selectItems("1", "4");
+ selectToTest.select("1", "4");
Assert.assertEquals(8, listenerCount.get());
}
@@ -154,88 +151,88 @@ public class AbstractMultiSelectTest {
});
rpcSelect("1");
- assertSelectionOrder(selectionModel, "1");
+ assertSelectionOrder("1");
rpcSelect("2");
- assertSelectionOrder(selectionModel, "1", "2");
- rpcDeselect("2");
- assertSelectionOrder(selectionModel, "1");
+ assertSelectionOrder("1", "2");
+ rpcDeselectItems("2");
+ assertSelectionOrder("1");
rpcSelect("3", "6");
- assertSelectionOrder(selectionModel, "1", "3", "6");
- rpcDeselect("1", "3");
- assertSelectionOrder(selectionModel, "6");
+ assertSelectionOrder("1", "3", "6");
+ rpcDeselectItems("1", "3");
+ assertSelectionOrder("6");
Assert.assertEquals(5, listenerCount.get());
// select partly selected
rpcSelect("2", "3", "4");
Assert.assertEquals(6, listenerCount.get());
- assertSelectionOrder(selectionModel, "6", "2", "3", "4");
+ assertSelectionOrder("6", "2", "3", "4");
// select completely selected
rpcSelect("2", "3", "4");
Assert.assertEquals(6, listenerCount.get());
- assertSelectionOrder(selectionModel, "6", "2", "3", "4");
+ assertSelectionOrder("6", "2", "3", "4");
// deselect partly not selected
- rpcDeselect("1", "4");
+ rpcDeselectItems("1", "4");
Assert.assertEquals(7, listenerCount.get());
- assertSelectionOrder(selectionModel, "6", "2", "3");
+ assertSelectionOrder("6", "2", "3");
// deselect completely not selected
- rpcDeselect("1", "4");
+ rpcDeselectItems("1", "4");
Assert.assertEquals(7, listenerCount.get());
- assertSelectionOrder(selectionModel, "6", "2", "3");
+ assertSelectionOrder("6", "2", "3");
// select completely selected and deselect completely not selected
rpcUpdateSelection(new String[] { "3" }, new String[] { "1", "4" });
Assert.assertEquals(7, listenerCount.get());
- assertSelectionOrder(selectionModel, "6", "2", "3");
+ assertSelectionOrder("6", "2", "3");
// select partly selected and deselect completely not selected
rpcUpdateSelection(new String[] { "4", "2" },
new String[] { "1", "8" });
Assert.assertEquals(8, listenerCount.get());
- assertSelectionOrder(selectionModel, "6", "2", "3", "4");
+ assertSelectionOrder("6", "2", "3", "4");
// select completely selected and deselect partly not selected
rpcUpdateSelection(new String[] { "4", "3" },
new String[] { "1", "2" });
Assert.assertEquals(9, listenerCount.get());
- assertSelectionOrder(selectionModel, "6", "3", "4");
+ assertSelectionOrder("6", "3", "4");
// duplicate case - ignored
rpcUpdateSelection(new String[] { "2" }, new String[] { "2" });
Assert.assertEquals(9, listenerCount.get());
- assertSelectionOrder(selectionModel, "6", "3", "4");
+ assertSelectionOrder("6", "3", "4");
// duplicate case - duplicate removed
rpcUpdateSelection(new String[] { "2" }, new String[] { "2", "3" });
Assert.assertEquals(10, listenerCount.get());
- assertSelectionOrder(selectionModel, "6", "4");
+ assertSelectionOrder("6", "4");
// duplicate case - duplicate removed
rpcUpdateSelection(new String[] { "6", "8" }, new String[] { "6" });
Assert.assertEquals(11, listenerCount.get());
- assertSelectionOrder(selectionModel, "6", "4", "8");
+ assertSelectionOrder("6", "4", "8");
}
@Test
public void getValue() {
- selectionModel.selectItems("1");
+ selectToTest.select("1");
Assert.assertEquals(Collections.singleton("1"),
selectToTest.getValue());
- selectionModel.deselectAll();
+ selectToTest.deselectAll();
LinkedHashSet<String> set = new LinkedHashSet<>();
set.add("1");
set.add("5");
- selectionModel.selectItems(set.toArray(new String[2]));
+ selectToTest.select(set.toArray(new String[2]));
Assert.assertEquals(set, selectToTest.getValue());
set.add("3");
- selectionModel.selectItems("3");
+ selectToTest.select("3");
Assert.assertEquals(set, selectToTest.getValue());
}
@@ -259,26 +256,21 @@ public class AbstractMultiSelectTest {
selectToTest.setValue(Collections.singleton("1"));
Assert.assertEquals(Collections.singleton("1"),
- selectionModel.getSelectedItems());
+ selectToTest.getSelectedItems());
Set<String> set = new LinkedHashSet<>();
set.add("4");
set.add("3");
selectToTest.setValue(set);
- Assert.assertEquals(set, selectionModel.getSelectedItems());
+ Assert.assertEquals(set, selectToTest.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;
- }
- };
+ AbstractMultiSelect<String> select = Mockito
+ .mock(AbstractMultiSelect.class);
Set set = new LinkedHashSet<>();
set.add("foo1");
@@ -287,11 +279,12 @@ public class AbstractMultiSelectTest {
selected.add("bar1");
selected.add("bar");
selected.add("bar2");
- Mockito.when(model.getSelectedItems()).thenReturn(selected);
+ Mockito.when(select.getSelectedItems()).thenReturn(selected);
+ Mockito.doCallRealMethod().when(select).setValue(Mockito.anySet());
select.setValue(set);
- Mockito.verify(model).updateSelection(set, selected);
+ Mockito.verify(select).updateSelection(set, selected);
}
@SuppressWarnings({ "unchecked", "serial" })
@@ -336,7 +329,7 @@ public class AbstractMultiSelectTest {
rpcUpdateSelection(keysToSelect, new String[] {});
}
- private void rpcDeselect(String... keysToDeselect) {
+ private void rpcDeselectItems(String... keysToDeselect) {
rpcUpdateSelection(new String[] {}, keysToDeselect);
}
@@ -353,9 +346,8 @@ public class AbstractMultiSelectTest {
.key(dataObject);
}
- private static void assertSelectionOrder(Multi<String> selectionModel,
- String... selectionOrder) {
+ private void assertSelectionOrder(String... selectionOrder) {
Assert.assertEquals(Arrays.asList(selectionOrder),
- new ArrayList<>(selectionModel.getSelectedItems()));
+ new ArrayList<>(selectToTest.getSelectedItems()));
}
}
diff --git a/server/src/test/java/com/vaadin/ui/AbstractSingleSelectTest.java b/server/src/test/java/com/vaadin/ui/AbstractSingleSelectTest.java
index 6ae5c91b96..47f5fbc81d 100644
--- a/server/src/test/java/com/vaadin/ui/AbstractSingleSelectTest.java
+++ b/server/src/test/java/com/vaadin/ui/AbstractSingleSelectTest.java
@@ -21,7 +21,6 @@ import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
@@ -34,13 +33,11 @@ import org.junit.Test;
import org.mockito.Mockito;
import com.vaadin.data.HasValue.ValueChangeEvent;
-import com.vaadin.data.SelectionModel.Multi;
import com.vaadin.event.selection.SingleSelectionChangeEvent;
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.ui.AbstractSingleSelect.AbstractSingleSelection;
/**
* Test for {@link AbstractSingleSelect} and {@link AbstractSingleSelection}
@@ -49,20 +46,15 @@ import com.vaadin.ui.AbstractSingleSelect.AbstractSingleSelection;
*/
public class AbstractSingleSelectTest {
- private PersonListing.AbstractSingleSelection selectionModel;
private List<Person> selectionChanges;
private static class PersonListing extends AbstractSingleSelect<Person> {
- public PersonListing() {
- setSelectionModel(new SimpleSingleSelection());
- }
}
@Before
public void initListing() {
listing = new PersonListing();
listing.setItems(PERSON_A, PERSON_B, PERSON_C);
- selectionModel = listing.getSelectionModel();
selectionChanges = new ArrayList<>();
listing.addSelectionListener(e -> selectionChanges.add(e.getValue()));
}
@@ -77,18 +69,17 @@ public class AbstractSingleSelectTest {
@Test
public void select() {
- selectionModel.select(PERSON_B);
+ listing.select(PERSON_B);
- assertTrue(selectionModel.getSelectedItem().isPresent());
+ assertTrue(listing.getSelectedItem().isPresent());
- assertEquals(PERSON_B, selectionModel.getSelectedItem().orElse(null));
+ assertEquals(PERSON_B, listing.getSelectedItem().orElse(null));
- assertFalse(selectionModel.isSelected(PERSON_A));
- assertTrue(selectionModel.isSelected(PERSON_B));
- assertFalse(selectionModel.isSelected(PERSON_C));
+ assertFalse(listing.isSelected(PERSON_A));
+ assertTrue(listing.isSelected(PERSON_B));
+ assertFalse(listing.isSelected(PERSON_C));
- assertEquals(Collections.singleton(PERSON_B),
- selectionModel.getSelectedItems());
+ assertEquals(Optional.of(PERSON_B), listing.getSelectedItem());
assertEquals(Arrays.asList(PERSON_B), selectionChanges);
}
@@ -96,16 +87,16 @@ public class AbstractSingleSelectTest {
@Test
public void selectDeselect() {
- selectionModel.select(PERSON_B);
- selectionModel.deselect(PERSON_B);
+ listing.select(PERSON_B);
+ listing.deselect(PERSON_B);
- assertFalse(selectionModel.getSelectedItem().isPresent());
+ assertFalse(listing.getSelectedItem().isPresent());
- assertFalse(selectionModel.isSelected(PERSON_A));
- assertFalse(selectionModel.isSelected(PERSON_B));
- assertFalse(selectionModel.isSelected(PERSON_C));
+ assertFalse(listing.isSelected(PERSON_A));
+ assertFalse(listing.isSelected(PERSON_B));
+ assertFalse(listing.isSelected(PERSON_C));
- assertTrue(selectionModel.getSelectedItems().isEmpty());
+ assertFalse(listing.getSelectedItem().isPresent());
assertEquals(Arrays.asList(PERSON_B, null), selectionChanges);
}
@@ -113,17 +104,16 @@ public class AbstractSingleSelectTest {
@Test
public void reselect() {
- selectionModel.select(PERSON_B);
- selectionModel.select(PERSON_C);
+ listing.select(PERSON_B);
+ listing.select(PERSON_C);
- assertEquals(PERSON_C, selectionModel.getSelectedItem().orElse(null));
+ assertEquals(PERSON_C, listing.getSelectedItem().orElse(null));
- assertFalse(selectionModel.isSelected(PERSON_A));
- assertFalse(selectionModel.isSelected(PERSON_B));
- assertTrue(selectionModel.isSelected(PERSON_C));
+ assertFalse(listing.isSelected(PERSON_A));
+ assertFalse(listing.isSelected(PERSON_B));
+ assertTrue(listing.isSelected(PERSON_C));
- assertEquals(Collections.singleton(PERSON_C),
- selectionModel.getSelectedItems());
+ assertEquals(Optional.of(PERSON_C), listing.getSelectedItem());
assertEquals(Arrays.asList(PERSON_B, PERSON_C), selectionChanges);
}
@@ -131,17 +121,16 @@ public class AbstractSingleSelectTest {
@Test
public void deselectNoOp() {
- selectionModel.select(PERSON_C);
- selectionModel.deselect(PERSON_B);
+ listing.select(PERSON_C);
+ listing.deselect(PERSON_B);
- assertEquals(PERSON_C, selectionModel.getSelectedItem().orElse(null));
+ assertEquals(PERSON_C, listing.getSelectedItem().orElse(null));
- assertFalse(selectionModel.isSelected(PERSON_A));
- assertFalse(selectionModel.isSelected(PERSON_B));
- assertTrue(selectionModel.isSelected(PERSON_C));
+ assertFalse(listing.isSelected(PERSON_A));
+ assertFalse(listing.isSelected(PERSON_B));
+ assertTrue(listing.isSelected(PERSON_C));
- assertEquals(Collections.singleton(PERSON_C),
- selectionModel.getSelectedItems());
+ assertEquals(Optional.of(PERSON_C), listing.getSelectedItem());
assertEquals(Arrays.asList(PERSON_C), selectionChanges);
}
@@ -149,17 +138,16 @@ public class AbstractSingleSelectTest {
@Test
public void selectTwice() {
- selectionModel.select(PERSON_C);
- selectionModel.select(PERSON_C);
+ listing.select(PERSON_C);
+ listing.select(PERSON_C);
- assertEquals(PERSON_C, selectionModel.getSelectedItem().orElse(null));
+ assertEquals(PERSON_C, listing.getSelectedItem().orElse(null));
- assertFalse(selectionModel.isSelected(PERSON_A));
- assertFalse(selectionModel.isSelected(PERSON_B));
- assertTrue(selectionModel.isSelected(PERSON_C));
+ assertFalse(listing.isSelected(PERSON_A));
+ assertFalse(listing.isSelected(PERSON_B));
+ assertTrue(listing.isSelected(PERSON_C));
- assertEquals(Collections.singleton(PERSON_C),
- selectionModel.getSelectedItems());
+ assertEquals(Optional.of(PERSON_C), listing.getSelectedItem());
assertEquals(Arrays.asList(PERSON_C), selectionChanges);
}
@@ -167,28 +155,28 @@ public class AbstractSingleSelectTest {
@Test
public void deselectTwice() {
- selectionModel.select(PERSON_C);
- selectionModel.deselect(PERSON_C);
- selectionModel.deselect(PERSON_C);
+ listing.select(PERSON_C);
+ listing.deselect(PERSON_C);
+ listing.deselect(PERSON_C);
- assertFalse(selectionModel.getSelectedItem().isPresent());
+ assertFalse(listing.getSelectedItem().isPresent());
- assertFalse(selectionModel.isSelected(PERSON_A));
- assertFalse(selectionModel.isSelected(PERSON_B));
- assertFalse(selectionModel.isSelected(PERSON_C));
+ assertFalse(listing.isSelected(PERSON_A));
+ assertFalse(listing.isSelected(PERSON_B));
+ assertFalse(listing.isSelected(PERSON_C));
- assertTrue(selectionModel.getSelectedItems().isEmpty());
+ assertFalse(listing.getSelectedItem().isPresent());
assertEquals(Arrays.asList(PERSON_C, null), selectionChanges);
}
@Test
public void getValue() {
- selectionModel.setSelectedItem(PERSON_B);
+ listing.setSelectedItem(PERSON_B);
Assert.assertEquals(PERSON_B, listing.getValue());
- selectionModel.deselectAll();
+ listing.deselect(PERSON_B);
Assert.assertNull(listing.getValue());
}
@@ -211,11 +199,11 @@ public class AbstractSingleSelectTest {
public void setValue() {
listing.setValue(PERSON_C);
- Assert.assertEquals(PERSON_C, selectionModel.getSelectedItem().get());
+ Assert.assertEquals(PERSON_C, listing.getSelectedItem().get());
listing.setValue(null);
- Assert.assertFalse(selectionModel.getSelectedItem().isPresent());
+ Assert.assertFalse(listing.getSelectedItem().isPresent());
}
@Test
@@ -268,15 +256,10 @@ public class AbstractSingleSelectTest {
}
@Test
- @SuppressWarnings({ "unchecked", "rawtypes", "serial" })
+ @SuppressWarnings({ "unchecked", "rawtypes" })
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;
- }
- };
+ AbstractMultiSelect<String> select = Mockito
+ .mock(AbstractMultiSelect.class);
Set set = new LinkedHashSet<>();
set.add("foo1");
@@ -285,11 +268,12 @@ public class AbstractSingleSelectTest {
selected.add("bar1");
selected.add("bar");
selected.add("bar2");
- Mockito.when(model.getSelectedItems()).thenReturn(selected);
+ Mockito.when(select.getSelectedItems()).thenReturn(selected);
+ Mockito.doCallRealMethod().when(select).setValue(Mockito.anySet());
select.setValue(set);
- Mockito.verify(model).updateSelection(set, selected);
+ Mockito.verify(select).updateSelection(set, selected);
}
}
diff --git a/server/src/test/java/com/vaadin/ui/RadioButtonGroupTest.java b/server/src/test/java/com/vaadin/ui/RadioButtonGroupTest.java
index 31bc2de271..ea1cf39351 100644
--- a/server/src/test/java/com/vaadin/ui/RadioButtonGroupTest.java
+++ b/server/src/test/java/com/vaadin/ui/RadioButtonGroupTest.java
@@ -23,14 +23,12 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
-import com.vaadin.data.SelectionModel;
import com.vaadin.data.SelectionModel.Multi;
import com.vaadin.server.data.DataSource;
import com.vaadin.shared.data.selection.SelectionServerRpc;
public class RadioButtonGroupTest {
private RadioButtonGroup<String> radioButtonGroup;
- private SelectionModel.Single<String> selectionModel;
@Before
public void setUp() {
@@ -38,7 +36,6 @@ public class RadioButtonGroupTest {
// Intentional deviation from upcoming selection order
radioButtonGroup
.setDataSource(DataSource.create("Third", "Second", "First"));
- selectionModel = radioButtonGroup.getSelectionModel();
}
@Test
@@ -54,7 +51,7 @@ public class RadioButtonGroupTest {
radioButtonGroup.select("Second");
radioButtonGroup.deselect("Second");
- radioButtonGroup.getSelectionModel().deselectAll();
+ radioButtonGroup.deselect("Second");
Assert.assertEquals(3, listenerCount.get());
}