]> source.dussan.org Git - vaadin-framework.git/commitdiff
Create MultiSelect interface to replace Multi selection model.
authorDenis Anisimov <denis@vaadin.com>
Wed, 2 Nov 2016 12:16:53 +0000 (14:16 +0200)
committerVaadin Code Review <review@vaadin.com>
Fri, 4 Nov 2016 12:02:50 +0000 (12:02 +0000)
Fixes vaadin/framework8-issues#423

Change-Id: Ifd252b8feed323708a7ae73af2b836832570d192

26 files changed:
server/src/main/java/com/vaadin/data/Listing.java
server/src/main/java/com/vaadin/event/selection/SingleSelectionChangeEvent.java
server/src/main/java/com/vaadin/ui/AbstractListing.java
server/src/main/java/com/vaadin/ui/AbstractMultiSelect.java
server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java
server/src/main/java/com/vaadin/ui/ComboBox.java
server/src/main/java/com/vaadin/ui/Grid.java
server/src/main/java/com/vaadin/ui/MultiSelect.java [new file with mode: 0644]
server/src/main/java/com/vaadin/ui/NativeSelect.java
server/src/main/java/com/vaadin/ui/RadioButtonGroup.java
server/src/test/java/com/vaadin/data/BinderMultiSelectTest.java
server/src/test/java/com/vaadin/tests/components/grid/GridSelectionTest.java
server/src/test/java/com/vaadin/ui/AbstractListingTest.java
server/src/test/java/com/vaadin/ui/AbstractMultiSelectTest.java
server/src/test/java/com/vaadin/ui/AbstractSingleSelectTest.java
server/src/test/java/com/vaadin/ui/RadioButtonGroupTest.java
uitest/src/main/java/com/vaadin/tests/components/AbstractListingFocusBlurTest.java
uitest/src/main/java/com/vaadin/tests/components/abstractlisting/AbstractListingTestUI.java
uitest/src/main/java/com/vaadin/tests/components/abstractlisting/AbstractMultiSelectTestUI.java
uitest/src/main/java/com/vaadin/tests/components/abstractlisting/AbstractSingleSelectTestUI.java
uitest/src/main/java/com/vaadin/tests/components/checkboxgroup/CheckBoxGroupFocusBlur.java
uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java
uitest/src/main/java/com/vaadin/tests/components/nativeselect/NativeSelectFocusBlur.java
uitest/src/main/java/com/vaadin/tests/components/radiobutton/RadioButtonGroupTestUI.java
uitest/src/main/java/com/vaadin/tests/components/radiobuttongroup/RadioButtonGroupFocusBlur.java
uitest/src/main/java/com/vaadin/tests/data/DummyData.java

index 397272a67787027c2c68fa4f8c502fc7a7fe1b44..422b3a112893124f2b4bfdae7ff872b17ed8f20d 100644 (file)
@@ -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.
@@ -51,13 +47,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.
      *
@@ -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);
-    }
 }
index 566facfd9cc585efe038128e97e81e95b34bc326..7f1acff82b53cb700684375fd5e7f244e81a4c9f 100644 (file)
@@ -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
index 3892e55662a9bdfee436e626b3590ebb347403a3..40d3001ca65ade7cb2c49143c08adac2398f3b6d 100644 (file)
@@ -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.
index 779cd959dd6031eec27cf38b49d6717f7da57d56..fc6ce4f0a4cb835e8ef13ede93689d5acfc07925 100644 (file)
@@ -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();
+    }
 }
index cb72d52444c3cd37b491ab4a989738c48d49b12f..7125139d8aa2f49e8c3cd8f369773c7bf1549e21 100644 (file)
@@ -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);
+                }
+            }
+        });
+    }
+
 }
index 8ceaec125c4957d47d2b37f7bd775e104a5b707a..097ae30bc70dc71e4cdcb262b83d34e7b4290c61 100644 (file)
@@ -55,24 +55,6 @@ import elemental.json.JsonObject;
 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;
+    }
+
 }
index bf50d6a53d8818722c94a98139d931f290736ca7..b738b713234759fc115985b3f750cf2f54c7ac08 100644 (file)
@@ -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 (file)
index 0000000..a3677d6
--- /dev/null
@@ -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);
+}
index bb3ae41df4c8030477f06d6813ed33b6d6c6eec8..a1ec0dca40f5e220ee8a55a81b44c6bcb87aef2f 100644 (file)
@@ -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());
     }
 
     /**
index 6f1191e8d433d9688c65971b4a0980ded526c055..4c5b814f224cc324da9455bcd42add0fe38285c8 100644 (file)
@@ -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);
                 }
index f8a4313b0938b2b27f9c67bcf2a9e29fc51ff208..c4725471da014312ad17acc6a14c8d2b7d1de348 100644 (file)
@@ -157,7 +157,7 @@ public class BinderMultiSelectTest
         converterBinder.readBean(new AtomicReference<>("TWO"));
 
         assertEquals(Collections.singleton(TestEnum.TWO),
-                select.getSelectionModel().getSelectedItems());
+                select.getSelectedItems());
     }
 
     @Test
index 0522e26ac98860e38be96580fd351336ae37f9ea..572413bb99ada42c0e945a2ea37137a054a8820a 100644 (file)
@@ -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());
     }
 
 }
index 585dce1f5e1e876516e337e153593e64a325185e..494fc2e1c562c5868f243572854884ba7621d793 100644 (file)
@@ -22,10 +22,6 @@ public class AbstractListingTest {
 
     private final class TestListing extends AbstractSingleSelect<String> {
 
-        protected TestListing() {
-            setSelectionModel(new SimpleSingleSelection());
-        }
-
         /**
          * Used to execute data generation
          */
index 6d748f076ac77eaeaa4c534cbdfa695467c632ee..92c288fc34cb2b7fb3cb0a2d93973fff74412af9 100644 (file)
@@ -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()));
     }
 }
index 6ae5c91b968beb1c86d76d8cff213835a86fa874..47f5fbc81d70daf7211319c384526857096c2ef4 100644 (file)
@@ -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);
     }
 
 }
index 31bc2de27189a24f80162186d81f25bc1ccbd9d8..ea1cf393510ecc1e7eab2d1fc728995bd462308e 100644 (file)
@@ -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());
     }
index f953c3acac3ff7fa4b4d63df8137db17590931c1..0d5ed5418066fe5e2c8fe90d0ae3e825b38bff45 100644 (file)
@@ -21,7 +21,6 @@ import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
 import com.googlecode.gentyref.GenericTypeReflector;
-import com.vaadin.data.SelectionModel;
 import com.vaadin.event.FieldEvents.BlurNotifier;
 import com.vaadin.event.FieldEvents.FocusNotifier;
 import com.vaadin.server.VaadinRequest;
@@ -31,7 +30,7 @@ import com.vaadin.ui.AbstractListing;
  * @author Vaadin Ltd
  *
  */
-public abstract class AbstractListingFocusBlurTest<T extends AbstractListing<Integer, S> & FocusNotifier & BlurNotifier, S extends SelectionModel<Integer>>
+public abstract class AbstractListingFocusBlurTest<T extends AbstractListing<Integer> & FocusNotifier & BlurNotifier>
         extends AbstractTestUIWithLog {
 
     @Override
@@ -45,7 +44,7 @@ public abstract class AbstractListingFocusBlurTest<T extends AbstractListing<Int
         if (valueType instanceof Class<?>) {
             Class<?> clazz = (Class<?>) valueType;
             try {
-                AbstractListing<Integer, ?> select = (AbstractListing<Integer, ?>) clazz
+                AbstractListing<Integer> select = (AbstractListing<Integer>) clazz
                         .newInstance();
                 select.setItems(
                         IntStream.range(1, 10).mapToObj(Integer::valueOf)
index 875c7d886f075f0784005225b461dffb8914753b..126eb4bf33cffb2a8c0328ccbc781895ec0a2c26 100644 (file)
@@ -8,7 +8,7 @@ import com.vaadin.tests.components.AbstractComponentTest;
 import com.vaadin.ui.AbstractListing;
 
 @Widgetset("com.vaadin.DefaultWidgetSet")
-public abstract class AbstractListingTestUI<T extends AbstractListing<Object, ?>>
+public abstract class AbstractListingTestUI<T extends AbstractListing<Object>>
         extends AbstractComponentTest<T> {
 
     @Override
index ae69cbb6ff6163baaad3c69ebf2b7576805275f3..89f9f9e0ead9f4d269a9a1dd70867e7e8f8bd408 100644 (file)
@@ -5,7 +5,6 @@ import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
-import com.vaadin.data.SelectionModel.Multi;
 import com.vaadin.ui.AbstractMultiSelect;
 import com.vaadin.ui.ItemCaptionGenerator;
 
@@ -38,10 +37,8 @@ public abstract class AbstractMultiSelectTestUI<MULTISELECT extends AbstractMult
     }
 
     protected void createSelectionMenu() {
-        createClickAction(
-                "Clear selection", selectionCategory, (component, item,
-                        data) -> component.getSelectionModel().deselectAll(),
-                "");
+        createClickAction("Clear selection", selectionCategory,
+                (component, item, data) -> component.deselectAll(), "");
 
         Command<MULTISELECT, String> toggleSelection = (component, item,
                 data) -> toggleSelection(item);
@@ -59,20 +56,18 @@ public abstract class AbstractMultiSelectTestUI<MULTISELECT extends AbstractMult
     }
 
     private void toggleSelection(String item) {
-        Multi<Object> selectionModel = getComponent().getSelectionModel();
-        if (selectionModel.isSelected(item)) {
-            selectionModel.deselect(item);
+        if (getComponent().isSelected(item)) {
+            getComponent().deselect(item);
         } else {
-            selectionModel.select(item);
+            getComponent().select(item);
         }
     }
 
     private void toggleMultiSelection(boolean add, List<String> items) {
-        Multi<Object> selectionModel = getComponent().getSelectionModel();
         if (add) {
-            selectionModel.selectItems(items.toArray());
+            getComponent().select(items.toArray());
         } else {
-            selectionModel.deselectItems(items.toArray());
+            getComponent().deselect(items.toArray());
         }
     }
 
index f9529ff2e3cdc5d225b2c6658523046fd35cb9ed..a3c43adc1f0b4073ad62c7a74be6f701967697f6 100644 (file)
@@ -45,11 +45,12 @@ public abstract class AbstractSingleSelectTestUI<T extends AbstractSingleSelect<
         options.put("Item 100", "Item 100");
 
         createSelectAction("Select", "Selection", options, "None",
-                (c, selected, data) -> {
+                (component, selected, data) -> {
                     if (selected != null) {
-                        c.select(selected);
+                        component.select(selected);
                     } else {
-                        c.getSelectedItems().forEach(c::deselect);
+                        component.getSelectedItem()
+                                .ifPresent(component::deselect);
                     }
                 });
     }
index b92132d9f7db67a0779044b3e7e7502951e20fff..d6d288b77d3354bd37ac704bedc820cb03162a1e 100644 (file)
@@ -15,7 +15,6 @@
  */
 package com.vaadin.tests.components.checkboxgroup;
 
-import com.vaadin.data.SelectionModel.Multi;
 import com.vaadin.tests.components.AbstractListingFocusBlurTest;
 import com.vaadin.ui.CheckBoxGroup;
 
@@ -28,7 +27,7 @@ import com.vaadin.ui.CheckBoxGroup;
  * @author Vaadin Ltd
  *
  */
-public class CheckBoxGroupFocusBlur extends
-        AbstractListingFocusBlurTest<CheckBoxGroup<Integer>, Multi<Integer>> {
+public class CheckBoxGroupFocusBlur
+        extends AbstractListingFocusBlurTest<CheckBoxGroup<Integer>> {
 
 }
index 4e9b1546280333b74c23dfba2068d2a45678ef87..96a2f313b9657d6950de22d7ad2ea326fcb4b832 100644 (file)
@@ -233,11 +233,9 @@ public class GridBasics extends AbstractTestUIWithLog {
             MenuItem headerTypeMenu = columnMenu.addItem("Header Type", null);
             headerTypeMenu.addItem("Text Header", selectedItem -> grid
                     .getDefaultHeaderRow().getCell(col).setText("Text Header"));
-            headerTypeMenu
-                    .addItem("HTML Header",
-                            selectedItem -> grid.getDefaultHeaderRow()
-                                    .getCell(col)
-                                    .setHtml("<b>HTML Header</b>"));
+            headerTypeMenu.addItem("HTML Header",
+                    selectedItem -> grid.getDefaultHeaderRow().getCell(col)
+                            .setHtml("<b>HTML Header</b>"));
             headerTypeMenu.addItem("Widget Header", selectedItem -> {
                 final Button button = new Button("Button Header");
                 button.addClickListener(clickEvent -> log("Button clicked!"));
@@ -293,15 +291,12 @@ public class GridBasics extends AbstractTestUIWithLog {
                         : null))
                 .setCheckable(true);
         stateMenu
-                .addItem("Cell description generator",
-                        item -> grid.getColumns().stream().findFirst()
-                                .ifPresent(
-                                        c -> c.setDescriptionGenerator(
-                                                item.isChecked()
-                                                        ? t -> "Cell tooltip for row "
-                                                                + t.getRowNumber()
-                                                                + ", Column 0"
-                                                        : null)))
+                .addItem("Cell description generator", item -> grid.getColumns()
+                        .stream().findFirst()
+                        .ifPresent(c -> c.setDescriptionGenerator(
+                                item.isChecked() ? t -> "Cell tooltip for row "
+                                        + t.getRowNumber() + ", Column 0"
+                                        : null)))
                 .setCheckable(true);
         stateMenu.addItem("Item click listener", new Command() {
 
@@ -393,10 +388,10 @@ public class GridBasics extends AbstractTestUIWithLog {
     private void createBodyMenu(MenuItem rowMenu) {
         rowMenu.addItem("Toggle first row selection", menuItem -> {
             DataObject item = data.get(0);
-            if (grid.isSelected(item)) {
-                grid.deselect(item);
+            if (grid.getSelectionModel().isSelected(item)) {
+                grid.getSelectionModel().deselect(item);
             } else {
-                grid.select(item);
+                grid.getSelectionModel().select(item);
             }
         });
     }
@@ -432,10 +427,9 @@ public class GridBasics extends AbstractTestUIWithLog {
     private void createFooterMenu(MenuItem footerMenu) {
         footerMenu.addItem("Add default footer row", menuItem -> {
             FooterRow defaultFooter = grid.appendFooterRow();
-            grid.getColumns()
-                    .forEach(column -> defaultFooter.getCell(column)
-                            .setText(grid.getDefaultHeaderRow().getCell(column)
-                                    .getText()));
+            grid.getColumns().forEach(
+                    column -> defaultFooter.getCell(column).setText(grid
+                            .getDefaultHeaderRow().getCell(column).getText()));
             footerMenu.removeChild(menuItem);
         });
         footerMenu.addItem("Append footer row", menuItem -> {
index b2664f892bb27942da425fd35d31f947d9da3f65..d0996612ec6d02943ba537b5842ea8d9f72c39d0 100644 (file)
@@ -16,7 +16,6 @@
 package com.vaadin.tests.components.nativeselect;
 
 import com.vaadin.tests.components.AbstractListingFocusBlurTest;
-import com.vaadin.ui.AbstractSingleSelect;
 import com.vaadin.ui.NativeSelect;
 
 /**
@@ -28,7 +27,7 @@ import com.vaadin.ui.NativeSelect;
  * @author Vaadin Ltd
  *
  */
-public class NativeSelectFocusBlur extends
-        AbstractListingFocusBlurTest<NativeSelect<Integer>, AbstractSingleSelect<Integer>.AbstractSingleSelection> {
+public class NativeSelectFocusBlur
+        extends AbstractListingFocusBlurTest<NativeSelect<Integer>> {
 
 }
index 3d8802c5ede90a25e7989fcede4ef00abcf878e0..7230eb9017c9b5b5542a667b71a23bf94cd2d61f 100644 (file)
  */
 package com.vaadin.tests.components.radiobutton;
 
-import com.vaadin.data.SelectionModel;
+import java.util.LinkedHashMap;
+import java.util.stream.IntStream;
+
 import com.vaadin.server.FontAwesome;
 import com.vaadin.tests.components.abstractlisting.AbstractListingTestUI;
 import com.vaadin.ui.ItemCaptionGenerator;
 import com.vaadin.ui.RadioButtonGroup;
 
-import java.util.LinkedHashMap;
-import java.util.stream.IntStream;
-
 /**
  * Test UI for RadioButtonGroup component
  *
@@ -50,9 +49,9 @@ public class RadioButtonGroupTestUI
     }
 
     protected void createSelectionMenu() {
-        createClickAction(
-                "Clear selection", selectionCategory, (component, item,
-                        data) -> component.getSelectionModel().deselectAll(),
+        createClickAction("Clear selection", selectionCategory,
+                (component, item, data) -> component.getSelectedItem()
+                        .ifPresent(component::deselect),
                 "");
 
         Command<RadioButtonGroup<Object>, String> toggleSelection = (component,
@@ -62,13 +61,14 @@ public class RadioButtonGroupTestUI
                 .forEach(item -> createClickAction("Toggle " + item,
                         selectionCategory, toggleSelection, item));
     }
+
     private void createItemIconGeneratorMenu() {
-        createBooleanAction("Use Item Icon Generator", "Item Icon Generator", false,
-                this::useItemIconGenerator);
+        createBooleanAction("Use Item Icon Generator", "Item Icon Generator",
+                false, this::useItemIconGenerator);
     }
 
     private void useItemIconGenerator(RadioButtonGroup<Object> group,
-                                     boolean activate, Object data) {
+            boolean activate, Object data) {
         if (activate) {
             group.setItemIconGenerator(
                     item -> FontAwesome.values()[getIndex(item) + 1]);
@@ -85,20 +85,18 @@ public class RadioButtonGroupTestUI
         options.put("Custom Caption Generator",
                 item -> item.toString() + " Caption");
 
-        createSelectAction("Item Caption Generator", "Item Caption Generator", options,
-                "None", (radioButtonGroup, captionGenerator, data) -> {
+        createSelectAction("Item Caption Generator", "Item Caption Generator",
+                options, "None", (radioButtonGroup, captionGenerator, data) -> {
                     radioButtonGroup.setItemCaptionGenerator(captionGenerator);
                     radioButtonGroup.getDataSource().refreshAll();
                 }, true);
     }
 
     private void toggleSelection(String item) {
-        SelectionModel.Single<Object> selectionModel = getComponent()
-                .getSelectionModel();
-        if (selectionModel.isSelected(item)) {
-            selectionModel.deselect(item);
+        if (getComponent().isSelected(item)) {
+            getComponent().deselect(item);
         } else {
-            selectionModel.select(item);
+            getComponent().select(item);
         }
     }
 
@@ -108,7 +106,6 @@ public class RadioButtonGroupTestUI
                         e -> log("Selected: " + e.getSelectedItem())));
     }
 
-
     private int getIndex(Object item) {
         int index = item.toString().indexOf(' ');
         if (index < 0) {
index 02238e5ef44e9c8a4cb1806449df1a0433f1c63a..1977ed5665c21f67664acd86ade181273f55ad89 100644 (file)
@@ -16,7 +16,6 @@
 package com.vaadin.tests.components.radiobuttongroup;
 
 import com.vaadin.tests.components.AbstractListingFocusBlurTest;
-import com.vaadin.ui.AbstractSingleSelect;
 import com.vaadin.ui.RadioButtonGroup;
 
 /**
@@ -28,7 +27,7 @@ import com.vaadin.ui.RadioButtonGroup;
  * @author Vaadin Ltd
  *
  */
-public class RadioButtonGroupFocusBlur extends
-        AbstractListingFocusBlurTest<RadioButtonGroup<Integer>, AbstractSingleSelect<Integer>.AbstractSingleSelection> {
+public class RadioButtonGroupFocusBlur
+        extends AbstractListingFocusBlurTest<RadioButtonGroup<Integer>> {
 
 }
index d0ba74a942438ba350797d6ebd4e9af1df9647e6..7157a205f41a132f718c27a024e06e75d80dc020 100644 (file)
@@ -4,19 +4,17 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.Set;
+import java.util.Optional;
 import java.util.stream.Stream;
 
 import com.vaadin.annotations.Widgetset;
-import com.vaadin.data.SelectionModel;
 import com.vaadin.server.VaadinRequest;
-import com.vaadin.server.data.DataCommunicator;
 import com.vaadin.server.data.ListDataSource;
 import com.vaadin.server.data.Query;
 import com.vaadin.shared.data.DataCommunicatorConstants;
 import com.vaadin.tests.components.AbstractTestUIWithLog;
 import com.vaadin.tests.widgetset.TestingWidgetSet;
-import com.vaadin.ui.AbstractListing;
+import com.vaadin.ui.AbstractSingleSelect;
 import com.vaadin.ui.Button;
 import com.vaadin.ui.HorizontalLayout;
 
@@ -44,26 +42,32 @@ public class DummyData extends AbstractTestUIWithLog {
      * Simplified server only selection model. Selection state passed in data,
      * shown as bold text.
      */
-    private static class DummySelectionModel implements SelectionModel<String> {
+    public static class DummyComponent extends AbstractSingleSelect<String> {
+
         private String selected;
-        private DataCommunicator<String> communicator;
+
+        private DummyComponent() {
+            addDataGenerator((str, json) -> {
+                json.put(DataCommunicatorConstants.DATA, str);
+                if (isSelected(str)) {
+                    json.put(DataCommunicatorConstants.SELECTED, true);
+                }
+            });
+        }
 
         @Override
-        public Set<String> getSelectedItems() {
-            if (selected != null) {
-                return Collections.singleton(selected);
-            }
-            return Collections.emptySet();
+        public Optional<String> getSelectedItem() {
+            return Optional.ofNullable(selected);
         }
 
         @Override
         public void select(String item) {
             if (selected != null) {
-                communicator.refresh(selected);
+                getDataCommunicator().refresh(selected);
             }
             selected = item;
             if (selected != null) {
-                communicator.refresh(selected);
+                getDataCommunicator().refresh(selected);
             }
         }
 
@@ -73,25 +77,6 @@ public class DummyData extends AbstractTestUIWithLog {
                 select(null);
             }
         }
-
-        private void setCommunicator(DataCommunicator<String> dataComm) {
-            communicator = dataComm;
-        }
-    }
-
-    public static class DummyComponent
-            extends AbstractListing<String, DummySelectionModel> {
-
-        private DummyComponent() {
-            setSelectionModel(new DummySelectionModel());
-            addDataGenerator((str, json) -> {
-                json.put(DataCommunicatorConstants.DATA, str);
-                if (isSelected(str)) {
-                    json.put(DataCommunicatorConstants.SELECTED, true);
-                }
-            });
-            getSelectionModel().setCommunicator(getDataCommunicator());
-        }
     }
 
     @Override