aboutsummaryrefslogtreecommitdiffstats
path: root/server/src
diff options
context:
space:
mode:
authorPekka Hyvönen <pekka@vaadin.com>2016-11-07 09:16:37 +0200
committerIlia Motornyi <elmot@vaadin.com>2016-11-10 07:49:08 +0000
commit39c15034076015a16cd056adf9dc422335985543 (patch)
tree8bb235b285e69cb48b83de067152f06d7c076e8d /server/src
parent0f42869ce1f81270141e94f169f1447febaff446 (diff)
downloadvaadin-framework-39c15034076015a16cd056adf9dc422335985543.tar.gz
vaadin-framework-39c15034076015a16cd056adf9dc422335985543.zip
Remove HasValue from Grid
Extracts grid single selection into separate class, which is an extension like in V7. Using an extension makes it possible to easily add multiselect and no-select modes back, and support custom selection models. Adds Grid:asSingleSelect() SingleSelect so that grid can be used as a Select in a binder. Removes all remaining references to SelectionModels in Listings. Renames SingleSelectionChangeEvent to SingleSelectionEvent, because then it is unified with selection listener and MultiSelectionEvent. Fixes vaadin/framework8-issues#424 Fixes vaadin/framework8-issues#425 Change-Id: Ie22bef29cfd4336c3f65d4e63531c578b8dd76a3
Diffstat (limited to 'server/src')
-rw-r--r--server/src/main/java/com/vaadin/data/SelectionModel.java21
-rw-r--r--server/src/main/java/com/vaadin/data/selection/AbstractSelectionModel.java47
-rw-r--r--server/src/main/java/com/vaadin/event/selection/SingleSelectionEvent.java (renamed from server/src/main/java/com/vaadin/event/selection/SingleSelectionChangeEvent.java)47
-rw-r--r--server/src/main/java/com/vaadin/event/selection/SingleSelectionListener.java6
-rw-r--r--server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java28
-rw-r--r--server/src/main/java/com/vaadin/ui/ComboBox.java2
-rw-r--r--server/src/main/java/com/vaadin/ui/Grid.java229
-rw-r--r--server/src/main/java/com/vaadin/ui/components/colorpicker/ColorPickerSelect.java24
-rw-r--r--server/src/main/java/com/vaadin/ui/components/grid/SingleSelectionModel.java299
-rw-r--r--server/src/test/java/com/vaadin/data/BinderSingleSelectTest.java12
-rw-r--r--server/src/test/java/com/vaadin/data/GridAsSingleSelectInBinder.java157
-rw-r--r--server/src/test/java/com/vaadin/event/selection/SelectionEventTest.java4
-rw-r--r--server/src/test/java/com/vaadin/tests/components/grid/GridSelectionTest.java36
-rw-r--r--server/src/test/java/com/vaadin/tests/components/grid/GridSingleSelectionModelTest.java244
-rw-r--r--server/src/test/java/com/vaadin/ui/AbstractSingleSelectTest.java79
-rw-r--r--server/src/test/java/com/vaadin/ui/RadioButtonGroupTest.java12
16 files changed, 864 insertions, 383 deletions
diff --git a/server/src/main/java/com/vaadin/data/SelectionModel.java b/server/src/main/java/com/vaadin/data/SelectionModel.java
index eca43e6c8d..98a068993a 100644
--- a/server/src/main/java/com/vaadin/data/SelectionModel.java
+++ b/server/src/main/java/com/vaadin/data/SelectionModel.java
@@ -90,6 +90,11 @@ public interface SelectionModel<T> extends Serializable {
return getSelectedItem().map(Collections::singleton)
.orElse(Collections.emptySet());
}
+
+ @Override
+ default Optional<T> getFirstSelectedItem() {
+ return getSelectedItem();
+ }
}
/**
@@ -173,6 +178,11 @@ public interface SelectionModel<T> extends Serializable {
* the items to remove, not {@code null}
*/
public void updateSelection(Set<T> addedItems, Set<T> removedItems);
+
+ @Override
+ default Optional<T> getFirstSelectedItem() {
+ return getSelectedItems().stream().findFirst();
+ }
}
/**
@@ -188,6 +198,17 @@ public interface SelectionModel<T> extends Serializable {
public Set<T> getSelectedItems();
/**
+ * Get first selected data item.
+ * <p>
+ * This is the same as {@link Single#getSelectedItem()} in case of single
+ * selection and the first selected item from
+ * {@link Multi#getSelectedItems()} in case of multiselection.
+ *
+ * @return the first selected item.
+ */
+ Optional<T> getFirstSelectedItem();
+
+ /**
* Selects the given item. Depending on the implementation, may cause other
* items to be deselected. If the item is already selected, does nothing.
*
diff --git a/server/src/main/java/com/vaadin/data/selection/AbstractSelectionModel.java b/server/src/main/java/com/vaadin/data/selection/AbstractSelectionModel.java
deleted file mode 100644
index 7e60847685..0000000000
--- a/server/src/main/java/com/vaadin/data/selection/AbstractSelectionModel.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.data.selection;
-
-import com.vaadin.data.SelectionModel;
-import com.vaadin.shared.data.DataCommunicatorConstants;
-import com.vaadin.ui.AbstractListing.AbstractListingExtension;
-
-import elemental.json.JsonObject;
-
-/**
- * An astract base class for {@code SelectionModel}s.
- *
- * @author Vaadin Ltd.
- *
- * @param <T>
- * type of selected data
- *
- * @since 8.0
- */
-public abstract class AbstractSelectionModel<T> extends
- AbstractListingExtension<T> implements SelectionModel<T> {
-
- @Override
- public void generateData(T data, JsonObject jsonObject) {
- if (isSelected(data)) {
- jsonObject.put(DataCommunicatorConstants.SELECTED, true);
- }
- }
-
- @Override
- public void destroyData(T data) {
- }
-}
diff --git a/server/src/main/java/com/vaadin/event/selection/SingleSelectionChangeEvent.java b/server/src/main/java/com/vaadin/event/selection/SingleSelectionEvent.java
index 7f1acff82b..c6c9ce6b6c 100644
--- a/server/src/main/java/com/vaadin/event/selection/SingleSelectionChangeEvent.java
+++ b/server/src/main/java/com/vaadin/event/selection/SingleSelectionEvent.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -18,45 +18,62 @@ package com.vaadin.event.selection;
import java.util.Optional;
import com.vaadin.data.HasValue.ValueChangeEvent;
-import com.vaadin.ui.AbstractListing;
import com.vaadin.ui.AbstractSingleSelect;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.SingleSelect;
/**
* Fired when the selection changes in a listing component.
- *
+ *
* @author Vaadin Ltd.
*
* @param <T>
* the type of the selected item
* @since 8.0
*/
-public class SingleSelectionChangeEvent<T> extends ValueChangeEvent<T>
+public class SingleSelectionEvent<T> extends ValueChangeEvent<T>
implements SelectionEvent<T> {
/**
* Creates a new selection change event.
- *
+ *
* @param source
* the listing that fired the event
* @param userOriginated
* {@code true} if this event originates from the client,
* {@code false} otherwise.
*/
- public SingleSelectionChangeEvent(AbstractSingleSelect<T> source,
+ public SingleSelectionEvent(AbstractSingleSelect<T> source,
boolean userOriginated) {
super(source, userOriginated);
}
/**
+ * Creates a new selection change event in a component.
+ *
+ * @param component
+ * the component where the event originated
+ * @param source
+ * the single select source
+ * @param userOriginated
+ * {@code true} if this event originates from the client,
+ * {@code false} otherwise.
+ */
+ public SingleSelectionEvent(Component component, SingleSelect<T> source,
+ boolean userOriginated) {
+ super(component, source, userOriginated);
+ }
+
+ /**
* Returns an optional of the item that was selected, or an empty optional
* if a previously selected item was deselected.
* <p>
* The result is the current selection of the source
* {@link AbstractSingleSelect} object. So it's always exactly the same as
* optional describing {@link AbstractSingleSelect#getValue()}.
- *
+ *
* @see #getValue()
- *
+ *
* @return the selected item or an empty optional if deselected
*
* @see SelectionModel.Single#getSelectedItem()
@@ -65,10 +82,14 @@ public class SingleSelectionChangeEvent<T> extends ValueChangeEvent<T>
return Optional.ofNullable(getValue());
}
+ /**
+ * The single select on which the Event initially occurred.
+ *
+ * @return The single select on which the Event initially occurred.
+ */
@Override
- @SuppressWarnings("unchecked")
- public AbstractListing<T> getComponent() {
- return (AbstractListing<T>) super.getComponent();
+ public SingleSelect<T> getSource() {
+ return (SingleSelect<T>) super.getSource();
}
@Override
diff --git a/server/src/main/java/com/vaadin/event/selection/SingleSelectionListener.java b/server/src/main/java/com/vaadin/event/selection/SingleSelectionListener.java
index d36c3ceaf1..eb054e250b 100644
--- a/server/src/main/java/com/vaadin/event/selection/SingleSelectionListener.java
+++ b/server/src/main/java/com/vaadin/event/selection/SingleSelectionListener.java
@@ -26,14 +26,14 @@ import java.util.function.Consumer;
* @param <T>
* the type of the selected item
*
- * @see SingleSelectionChangeEvent
+ * @see SingleSelectionEvent
*
* @since 8.0
*/
@FunctionalInterface
public interface SingleSelectionListener<T>
- extends Consumer<SingleSelectionChangeEvent<T>>, Serializable {
+ extends Consumer<SingleSelectionEvent<T>>, Serializable {
@Override
- public void accept(SingleSelectionChangeEvent<T> event);
+ public void accept(SingleSelectionEvent<T> event);
}
diff --git a/server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java b/server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java
index 7125139d8a..2ffcedde15 100644
--- a/server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java
+++ b/server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java
@@ -22,7 +22,7 @@ import java.util.Optional;
import com.vaadin.data.HasValue;
import com.vaadin.data.SelectionModel;
import com.vaadin.data.SelectionModel.Single;
-import com.vaadin.event.selection.SingleSelectionChangeEvent;
+import com.vaadin.event.selection.SingleSelectionEvent;
import com.vaadin.event.selection.SingleSelectionListener;
import com.vaadin.server.data.DataCommunicator;
import com.vaadin.shared.Registration;
@@ -49,7 +49,7 @@ public abstract class AbstractSingleSelect<T> extends AbstractListing<T>
@Deprecated
private static final Method SELECTION_CHANGE_METHOD = ReflectTools
.findMethod(SingleSelectionListener.class, "accept",
- SingleSelectionChangeEvent.class);
+ SingleSelectionEvent.class);
/**
* Creates a new {@code AbstractListing} with a default data communicator.
@@ -92,11 +92,11 @@ public abstract class AbstractSingleSelect<T> extends AbstractListing<T>
* the value change listener, not null
* @return a registration for the listener
*/
- public Registration addSelectionListener(
+ public Registration addSelectionChangeListener(
SingleSelectionListener<T> listener) {
- addListener(SingleSelectionChangeEvent.class, listener,
+ addListener(SingleSelectionEvent.class, listener,
SELECTION_CHANGE_METHOD);
- return () -> removeListener(SingleSelectionChangeEvent.class, listener);
+ return () -> removeListener(SingleSelectionEvent.class, listener);
}
/**
@@ -158,7 +158,7 @@ public abstract class AbstractSingleSelect<T> extends AbstractListing<T>
@Override
public Registration addValueChangeListener(
HasValue.ValueChangeListener<T> listener) {
- return addSelectionListener(event -> listener.accept(
+ return addSelectionChangeListener(event -> listener.accept(
new ValueChangeEvent<>(this, event.isUserOriginated())));
}
@@ -192,18 +192,6 @@ public abstract class AbstractSingleSelect<T> extends AbstractListing<T>
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.
@@ -245,7 +233,7 @@ public abstract class AbstractSingleSelect<T> extends AbstractListing<T>
}
doSetSelectedKey(key);
- fireEvent(new SingleSelectionChangeEvent<>(AbstractSingleSelect.this,
+ fireEvent(new SingleSelectionEvent<>(AbstractSingleSelect.this,
true));
}
@@ -266,7 +254,7 @@ public abstract class AbstractSingleSelect<T> extends AbstractListing<T>
}
doSetSelectedKey(key);
- fireEvent(new SingleSelectionChangeEvent<>(AbstractSingleSelect.this,
+ fireEvent(new SingleSelectionEvent<>(AbstractSingleSelect.this,
false));
}
diff --git a/server/src/main/java/com/vaadin/ui/ComboBox.java b/server/src/main/java/com/vaadin/ui/ComboBox.java
index 097ae30bc7..d4df2236f7 100644
--- a/server/src/main/java/com/vaadin/ui/ComboBox.java
+++ b/server/src/main/java/com/vaadin/ui/ComboBox.java
@@ -524,7 +524,7 @@ public class ComboBox<T> extends AbstractSingleSelect<T> implements HasValue<T>,
@Override
public Registration addValueChangeListener(
HasValue.ValueChangeListener<T> listener) {
- return addSelectionListener(event -> {
+ return addSelectionChangeListener(event -> {
listener.accept(new ValueChangeEvent<>(event.getComponent(), this,
event.isUserOriginated()));
});
diff --git a/server/src/main/java/com/vaadin/ui/Grid.java b/server/src/main/java/com/vaadin/ui/Grid.java
index 63c8fe3e6f..42aab6a7e4 100644
--- a/server/src/main/java/com/vaadin/ui/Grid.java
+++ b/server/src/main/java/com/vaadin/ui/Grid.java
@@ -30,19 +30,19 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.Optional;
import java.util.Set;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import com.vaadin.data.SelectionModel.Single;
+import com.vaadin.data.Binder;
+import com.vaadin.data.SelectionModel;
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.Extension;
import com.vaadin.server.JsonCodec;
import com.vaadin.server.SerializableComparator;
import com.vaadin.server.SerializableFunction;
@@ -50,7 +50,6 @@ 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;
@@ -65,6 +64,7 @@ import com.vaadin.ui.Grid.FooterRow;
import com.vaadin.ui.components.grid.Footer;
import com.vaadin.ui.components.grid.Header;
import com.vaadin.ui.components.grid.Header.Row;
+import com.vaadin.ui.components.grid.SingleSelectionModel;
import com.vaadin.ui.renderers.AbstractRenderer;
import com.vaadin.ui.renderers.Renderer;
import com.vaadin.ui.renderers.TextRenderer;
@@ -83,7 +83,7 @@ import elemental.json.JsonValue;
* @param <T>
* the grid bean type
*/
-public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents {
+public class Grid<T> extends AbstractListing<T> implements HasComponents {
@Deprecated
private static final Method COLUMN_REORDER_METHOD = ReflectTools.findMethod(
@@ -121,6 +121,27 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents {
}
/**
+ * The server-side interface that controls Grid's selection state.
+ * SelectionModel should extend {@link AbstractGridExtension}.
+ *
+ * @param <T>
+ * the grid bean type
+ */
+ public interface GridSelectionModel<T>
+ extends SelectionModel<T>, Extension {
+
+ /**
+ * Removes this selection model from the grid.
+ * <p>
+ * Must call super {@link Extension#remove()} to detach the extension,
+ * and fire an selection change event for the selection model (with an
+ * empty selection).
+ */
+ @Override
+ void remove();
+ }
+
+ /**
* An event listener for column resize events in the Grid.
*/
@FunctionalInterface
@@ -602,8 +623,8 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents {
.hasKey(diffStateKey) : "Field name has changed";
Type type = null;
try {
- type = (getState(false).getClass()
- .getDeclaredField(diffStateKey).getGenericType());
+ type = getState(false).getClass()
+ .getDeclaredField(diffStateKey).getGenericType();
} catch (NoSuchFieldException | SecurityException e) {
e.printStackTrace();
}
@@ -1488,163 +1509,6 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents {
}
}
- private final class SingleSelection implements Single<T> {
- private T selectedItem = null;
-
- SingleSelection() {
- addDataGenerator((item, json) -> {
- if (isSelected(item)) {
- 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
- public Optional<T> getSelectedItem() {
- return Optional.ofNullable(selectedItem);
- }
-
- @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());
- }
-
- /**
- * 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);
- }
-
- /**
- * 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);
- }
- selectedItem = keyToItem(key);
- if (selectedItem != null) {
- 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);
- }
- }
-
/**
* A header row in a Grid.
*/
@@ -1835,17 +1699,18 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents {
private int counter = 0;
- private Single<T> selectionModel;
+ private GridSelectionModel<T> selectionModel;
/**
* Constructor for the {@link Grid} component.
*/
public Grid() {
- setSelectionModel(new SingleSelection());
registerRpc(new GridServerRpcImpl());
setDefaultHeaderRow(appendHeaderRow());
+ selectionModel = new SingleSelectionModel<>(this);
+
detailsManager = new DetailsManager<>();
addExtension(detailsManager);
addDataGenerator(detailsManager);
@@ -2690,30 +2555,40 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents {
*
* @return the selection model, not null
*/
- public Single<T> getSelectionModel() {
+ public GridSelectionModel<T> getSelectionModel() {
assert selectionModel != null : "No selection model set by "
+ getClass().getName() + " constructor";
return selectionModel;
}
- @Override
- public Optional<T> getSelectedItem() {
- return getSelectionModel().getSelectedItem();
+ /**
+ * Use this grid as a single select in {@link Binder}.
+ * <p>
+ * Sets the grid to single select mode, if not yet so.
+ *
+ * @return the single select wrapper that can be used in binder
+ */
+ public SingleSelect<T> asSingleSelect() {
+ GridSelectionModel<T> model = getSelectionModel();
+ if (!(model instanceof SingleSelectionModel)) {
+ model = new SingleSelectionModel<>(this);
+ setSelectionModel(model);
+ }
+
+ return ((SingleSelectionModel<T>) model).asSingleSelect();
}
/**
* Sets the selection model for this listing.
+ * <p>
+ * The default selection model is {@link SingleSelectionModel}.
*
* @param model
- * the selection model to use, not null
+ * the selection model to use, not {@code null}
*/
- protected void setSelectionModel(Single<T> model) {
- if (selectionModel != null) {
- throw new IllegalStateException(
- "A selection model can't be changed.");
- }
-
+ protected void setSelectionModel(GridSelectionModel<T> model) {
Objects.requireNonNull(model, "selection model cannot be null");
+ selectionModel.remove();
selectionModel = model;
}
diff --git a/server/src/main/java/com/vaadin/ui/components/colorpicker/ColorPickerSelect.java b/server/src/main/java/com/vaadin/ui/components/colorpicker/ColorPickerSelect.java
index ec200082ab..f762aae827 100644
--- a/server/src/main/java/com/vaadin/ui/components/colorpicker/ColorPickerSelect.java
+++ b/server/src/main/java/com/vaadin/ui/components/colorpicker/ColorPickerSelect.java
@@ -62,7 +62,7 @@ public class ColorPickerSelect extends CustomField<Color> {
range.setWidth("100%");
range.addValueChangeListener(this::valueChange);
- range.select(ColorRange.ALL);
+ range.setValue(ColorRange.ALL);
layout.addComponent(range);
@@ -90,20 +90,20 @@ public class ColorPickerSelect extends CustomField<Color> {
for (int row = 0; row < rows; row++) {
for (int col = 0; col < columns; col++) {
- if (row < (rows - 1)) {
+ if (row < rows - 1) {
// Create the color grid by varying the saturation and value
// Calculate new hue value
- float hue = ((float) col / (float) columns);
+ float hue = (float) col / (float) columns;
float saturation = 1f;
float value = 1f;
// For the upper half use value=1 and variable
// saturation
- if (row < (rows / 2)) {
- saturation = ((row + 1f) / (rows / 2f));
+ if (row < rows / 2) {
+ saturation = (row + 1f) / (rows / 2f);
} else {
- value = 1f - ((row - (rows / 2f)) / (rows / 2f));
+ value = 1f - (row - rows / 2f) / (rows / 2f);
}
colors[row][col] = new Color(
@@ -112,7 +112,7 @@ public class ColorPickerSelect extends CustomField<Color> {
// The last row should have the black&white gradient
float hue = 0f;
float saturation = 0f;
- float value = 1f - ((float) col / (float) columns);
+ float value = 1f - (float) col / (float) columns;
colors[row][col] = new Color(
Color.HSVtoRGB(hue, saturation, value));
@@ -151,13 +151,11 @@ public class ColorPickerSelect extends CustomField<Color> {
saturation = 1f;
value = 1f;
- if (index <= ((rows * columns) / 2)) {
- saturation = index
- / (((float) rows * (float) columns) / 2f);
+ if (index <= rows * columns / 2) {
+ saturation = index / ((float) rows * (float) columns / 2f);
} else {
- index -= ((rows * columns) / 2);
- value = 1f
- - index / (((float) rows * (float) columns) / 2f);
+ index -= rows * columns / 2;
+ value = 1f - index / ((float) rows * (float) columns / 2f);
}
colors[row][col] = new Color(
diff --git a/server/src/main/java/com/vaadin/ui/components/grid/SingleSelectionModel.java b/server/src/main/java/com/vaadin/ui/components/grid/SingleSelectionModel.java
new file mode 100644
index 0000000000..bf2f55648e
--- /dev/null
+++ b/server/src/main/java/com/vaadin/ui/components/grid/SingleSelectionModel.java
@@ -0,0 +1,299 @@
+/*
+ * 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.components.grid;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+import com.vaadin.data.SelectionModel;
+import com.vaadin.event.selection.SingleSelectionEvent;
+import com.vaadin.event.selection.SingleSelectionListener;
+import com.vaadin.shared.Registration;
+import com.vaadin.shared.data.DataCommunicatorConstants;
+import com.vaadin.shared.data.selection.SelectionServerRpc;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Grid;
+import com.vaadin.ui.Grid.AbstractGridExtension;
+import com.vaadin.ui.Grid.GridSelectionModel;
+import com.vaadin.ui.SingleSelect;
+import com.vaadin.util.ReflectTools;
+
+import elemental.json.JsonObject;
+
+/**
+ * Single selection model for grid.
+ *
+ * @author Vaadin Ltd.
+ * @since 8.0
+ *
+ * @param <T>
+ * the type of the selected item in grid.
+ */
+public class SingleSelectionModel<T> extends AbstractGridExtension<T>
+ implements GridSelectionModel<T>, SelectionModel.Single<T> {
+
+ private static final Method SELECTION_CHANGE_METHOD = ReflectTools
+ .findMethod(SingleSelectionListener.class, "accept",
+ SingleSelectionEvent.class);
+
+ private final Grid<T> grid;
+ private T selectedItem = null;
+
+ /**
+ * Constructs a new single selection model for the given grid.
+ *
+ * @param grid
+ * the grid to bind the selection model into
+ */
+ public SingleSelectionModel(Grid<T> grid) {
+ this.grid = grid;
+ extend(grid);
+ registerRpc(new SelectionServerRpc() {
+
+ @Override
+ public void select(String key) {
+ setSelectedFromClient(key);
+ }
+
+ @Override
+ public void deselect(String key) {
+ if (isKeySelected(key)) {
+ setSelectedFromClient(null);
+ }
+ }
+ });
+ }
+
+ /**
+ * Adds a selection change listener to this select. The listener is called
+ * when the value of this select is changed either by the user or
+ * programmatically.
+ *
+ * @param listener
+ * the value change listener, not null
+ * @return a registration for the listener
+ */
+ public Registration addSelectionChangeListener(
+ SingleSelectionListener<T> listener) {
+ addListener(SingleSelectionEvent.class, listener,
+ SELECTION_CHANGE_METHOD);
+ return () -> removeListener(SingleSelectionEvent.class, listener);
+ }
+
+ @Override
+ public Optional<T> getSelectedItem() {
+ return Optional.ofNullable(selectedItem);
+ }
+
+ @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());
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * 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) {
+ grid.getDataCommunicator().refresh(selectedItem);
+ }
+ selectedItem = getData(key);
+ if (selectedItem != null) {
+ grid.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 (isKeySelected(key)) {
+ return;
+ }
+
+ doSetSelectedKey(key);
+ fireEvent(
+ new SingleSelectionEvent<>(grid, asSingleSelect(), 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 (isSelected(item) || isKeySelected(key)) {
+ return;
+ }
+
+ doSetSelectedKey(key);
+ fireEvent(new SingleSelectionEvent<>(grid, asSingleSelect(),
+ 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 grid.getDataCommunicator().getKeyMapper().key(item);
+ }
+ }
+
+ @Override
+ public Set<T> getSelectedItems() {
+ if (selectedItem != null) {
+ return new HashSet<>(Arrays.asList(selectedItem));
+ } else {
+ return Collections.emptySet();
+ }
+ }
+
+ @Override
+ public void generateData(T item, JsonObject jsonObject) {
+ if (isSelected(item)) {
+ jsonObject.put(DataCommunicatorConstants.SELECTED, true);
+ }
+ }
+
+ @Override
+ public void remove() {
+ // when selection model changes, firing an event for selection change
+ // event fired before removing so that parent is still intact (in case
+ // needed)
+ selectedItem = null;
+ fireEvent(new SingleSelectionEvent<>(grid, asSingleSelect(),
+ false));
+
+ super.remove();
+ }
+
+ /**
+ * Gets a wrapper for using this grid as a single select in a binder.
+ *
+ * @return a single select wrapper for grid
+ */
+ public SingleSelect<T> asSingleSelect() {
+ return new SingleSelect<T>() {
+
+ @Override
+ public void setValue(T value) {
+ SingleSelectionModel.this.setSelectedFromServer(value);
+ }
+
+ @Override
+ public T getValue() {
+ return SingleSelectionModel.this.getSelectedItem().orElse(null);
+ }
+
+ @Override
+ public Registration addValueChangeListener(
+ com.vaadin.data.HasValue.ValueChangeListener<T> listener) {
+ return SingleSelectionModel.this.addSelectionChangeListener(
+ event -> listener.accept(event));
+ }
+
+ @Override
+ public void setRequiredIndicatorVisible(
+ boolean requiredIndicatorVisible) {
+ // TODO support required indicator when grid is used in binder ?
+ throw new UnsupportedOperationException(
+ "Required indicator is not supported for Grid.");
+ }
+
+ @Override
+ public boolean isRequiredIndicatorVisible() {
+ throw new UnsupportedOperationException(
+ "Required indicator is not supported for Grid.");
+ }
+
+ @Override
+ public void setReadOnly(boolean readOnly) {
+ // TODO support read only when grid is used in binder ?
+ throw new UnsupportedOperationException(
+ "Read only is not supported for Grid.");
+ }
+
+ @Override
+ public boolean isReadOnly() {
+ throw new UnsupportedOperationException(
+ "Read only is not supported for Grid.");
+ }
+ };
+ }
+} \ No newline at end of file
diff --git a/server/src/test/java/com/vaadin/data/BinderSingleSelectTest.java b/server/src/test/java/com/vaadin/data/BinderSingleSelectTest.java
index 00a946247d..a0ebe374fb 100644
--- a/server/src/test/java/com/vaadin/data/BinderSingleSelectTest.java
+++ b/server/src/test/java/com/vaadin/data/BinderSingleSelectTest.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -76,7 +76,7 @@ public class BinderSingleSelectTest
public void bound_setSelection_beanValueUpdated() {
bindSex();
- select.select(Sex.MALE);
+ select.setValue(Sex.MALE);
assertSame(Sex.MALE, item.getSex());
}
@@ -86,7 +86,7 @@ public class BinderSingleSelectTest
item.setSex(Sex.MALE);
bindSex();
- select.deselect(Sex.MALE);
+ select.setValue(null);
assertNull(item.getSex());
}
@@ -97,7 +97,7 @@ public class BinderSingleSelectTest
bindSex();
binder.removeBean();
- select.select(Sex.FEMALE);
+ select.setValue(Sex.FEMALE);
assertSame(Sex.UNKNOWN, item.getSex());
}
diff --git a/server/src/test/java/com/vaadin/data/GridAsSingleSelectInBinder.java b/server/src/test/java/com/vaadin/data/GridAsSingleSelectInBinder.java
new file mode 100644
index 0000000000..7b34c78f25
--- /dev/null
+++ b/server/src/test/java/com/vaadin/data/GridAsSingleSelectInBinder.java
@@ -0,0 +1,157 @@
+package com.vaadin.data;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.vaadin.tests.data.bean.Person;
+import com.vaadin.tests.data.bean.Sex;
+import com.vaadin.ui.Grid;
+import com.vaadin.ui.SingleSelect;
+import com.vaadin.ui.components.grid.SingleSelectionModel;
+
+public class GridAsSingleSelectInBinder
+ extends BinderTestBase<Binder<Person>, Person> {
+
+ private class GridWithCustomSingleSelectionModel extends Grid<Sex> {
+ @Override
+ public void setSelectionModel(
+ com.vaadin.ui.Grid.GridSelectionModel<Sex> model) {
+ super.setSelectionModel(model);
+ }
+ }
+
+ private class CustomSingleSelectModel extends SingleSelectionModel<Sex> {
+
+ public CustomSingleSelectModel(Grid<Sex> grid) {
+ super(grid);
+ }
+
+ public void setSelectedFromClient(Sex item) {
+ setSelectedFromClient(itemToKey(item));
+ }
+ }
+
+ private Grid<Sex> grid;
+ private SingleSelect<Sex> select;
+
+ @Before
+ public void setup() {
+ binder = new Binder<>();
+ item = new Person();
+ grid = new Grid<>();
+ grid.setItems(Sex.values());
+ select = grid.asSingleSelect();
+ }
+
+ @Test
+ public void personBound_bindSelectByShortcut_selectionUpdated() {
+ item.setSex(Sex.FEMALE);
+ binder.setBean(item);
+ binder.bind(select, Person::getSex, Person::setSex);
+
+ assertSame(Sex.FEMALE, select.getValue());
+ }
+
+ @Test
+ public void personBound_bindSelect_selectionUpdated() {
+ item.setSex(Sex.MALE);
+ binder.setBean(item);
+ binder.forField(select).bind(Person::getSex, Person::setSex);
+
+ assertSame(Sex.MALE, select.getValue());
+ }
+
+ @Test
+ public void selectBound_bindPersonWithNullSex_selectedItemNotPresent() {
+ bindSex();
+
+ assertFalse(select.getValue() != null);
+ }
+
+ @Test
+ public void selectBound_bindPerson_selectionUpdated() {
+ item.setSex(Sex.FEMALE);
+ bindSex();
+
+ assertSame(Sex.FEMALE, select.getValue());
+ }
+
+ @Test
+ public void bound_setSelection_beanValueUpdated() {
+ bindSex();
+
+ select.setValue(Sex.MALE);
+
+ assertSame(Sex.MALE, item.getSex());
+ }
+
+ @Test
+ public void bound_deselect_beanValueUpdatedToNull() {
+ item.setSex(Sex.MALE);
+ bindSex();
+
+ select.setValue(null);
+
+ assertNull(item.getSex());
+ }
+
+ @Test
+ public void unbound_changeSelection_beanValueNotUpdated() {
+ item.setSex(Sex.UNKNOWN);
+ bindSex();
+ binder.removeBean();
+
+ select.setValue(Sex.FEMALE);
+
+ assertSame(Sex.UNKNOWN, item.getSex());
+ }
+
+ @Test
+ public void addValueChangeListener_selectionUpdated_eventTriggeredForSelect() {
+ binder = new Binder<>();
+ item = new Person();
+ GridWithCustomSingleSelectionModel grid = new GridWithCustomSingleSelectionModel();
+ CustomSingleSelectModel model = new CustomSingleSelectModel(grid);
+ grid.setSelectionModel(model);
+ grid.setItems(Sex.values());
+ select = grid.asSingleSelect();
+
+ List<Sex> selected = new ArrayList<>();
+ List<Boolean> userOriginated = new ArrayList<>();
+ select.addValueChangeListener(event -> {
+ selected.add(event.getValue());
+ userOriginated.add(event.isUserOriginated());
+ assertSame(grid, event.getComponent());
+ // cannot compare that the event source is the select since a new
+ // SingleSelect wrapper object has been created for the event
+ assertSame(select.getValue(), event.getValue());
+ });
+
+ grid.getSelectionModel().select(Sex.UNKNOWN);
+ model.setSelectedFromClient(Sex.MALE); // simulates client side
+ // selection
+ grid.getSelectionModel().select(Sex.MALE); // NOOP
+ grid.getSelectionModel().deselect(Sex.UNKNOWN); // NOOP
+ model.setSelectedFromClient(null); // simulates deselect from client
+ // side
+ grid.getSelectionModel().select(Sex.FEMALE);
+
+ assertEquals(Arrays.asList(Sex.UNKNOWN, Sex.MALE, null, Sex.FEMALE),
+ selected);
+ assertEquals(Arrays.asList(false, true, true, false), userOriginated);
+ }
+
+ protected void bindSex() {
+ binder.forField(select).bind(Person::getSex, Person::setSex);
+ binder.setBean(item);
+ }
+}
diff --git a/server/src/test/java/com/vaadin/event/selection/SelectionEventTest.java b/server/src/test/java/com/vaadin/event/selection/SelectionEventTest.java
index 006025c197..97a6ed03d1 100644
--- a/server/src/test/java/com/vaadin/event/selection/SelectionEventTest.java
+++ b/server/src/test/java/com/vaadin/event/selection/SelectionEventTest.java
@@ -51,8 +51,8 @@ public class SelectionEventTest {
@SuppressWarnings({ "unchecked", "rawtypes" })
@Test
public void getFirstSelected_singleSelectEvent() {
- SingleSelectionChangeEvent event = Mockito
- .mock(SingleSelectionChangeEvent.class);
+ SingleSelectionEvent event = Mockito
+ .mock(SingleSelectionEvent.class);
Mockito.doCallRealMethod().when(event).getFirstSelected();
Mockito.when(event.getSelectedItem()).thenReturn(Optional.of("foo"));
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
deleted file mode 100644
index 572413bb99..0000000000
--- a/server/src/test/java/com/vaadin/tests/components/grid/GridSelectionTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.vaadin.tests.components.grid;
-
-import java.util.Optional;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.vaadin.ui.Grid;
-
-public class GridSelectionTest {
-
- Grid<String> grid;
-
- @Before
- public void setUp() {
- grid = new Grid<>();
- grid.setItems("Foo", "Bar");
- }
-
- @Test
- public void testGridWithSingleSelection() {
- 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/tests/components/grid/GridSingleSelectionModelTest.java b/server/src/test/java/com/vaadin/tests/components/grid/GridSingleSelectionModelTest.java
new file mode 100644
index 0000000000..9746e2eef1
--- /dev/null
+++ b/server/src/test/java/com/vaadin/tests/components/grid/GridSingleSelectionModelTest.java
@@ -0,0 +1,244 @@
+package com.vaadin.tests.components.grid;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import com.vaadin.data.HasValue.ValueChangeEvent;
+import com.vaadin.event.selection.SingleSelectionEvent;
+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.Grid;
+import com.vaadin.ui.Grid.GridSelectionModel;
+import com.vaadin.ui.components.grid.SingleSelectionModel;
+
+public class GridSingleSelectionModelTest {
+
+ public static final Person PERSON_C = new Person("c", 3);
+ public static final Person PERSON_B = new Person("b", 2);
+ public static final Person PERSON_A = new Person("a", 1);
+ public static final String RPC_INTERFACE = DataCommunicatorClientRpc.class
+ .getName();
+
+ private class CustomSelectionModelGrid extends Grid<String> {
+ public void switchSelectionModel() {
+ // just switch selection model to cause event
+ setSelectionModel(new SingleSelectionModel(this));
+ }
+ }
+
+ private List<Person> selectionChanges;
+ private Grid<Person> grid;
+ private SingleSelectionModel<Person> selectionModel;
+
+ @Before
+ public void setUp() {
+ grid = new Grid<>();
+ grid.setItems(PERSON_A, PERSON_B, PERSON_C);
+ selectionModel = (SingleSelectionModel<Person>) grid
+ .getSelectionModel();
+
+ selectionChanges = new ArrayList<>();
+ selectionModel.addSelectionChangeListener(
+ e -> selectionChanges.add(e.getValue()));
+ }
+
+ @Test
+ public void testGridChangingSelectionModel_firesSelectionChangeEvent() {
+ CustomSelectionModelGrid customGrid = new CustomSelectionModelGrid();
+ customGrid.setItems("Foo", "Bar", "Baz");
+
+ List<String> selectionChanges = new ArrayList<>();
+ ((SingleSelectionModel<String>) customGrid.getSelectionModel())
+ .addSelectionChangeListener(
+ e -> selectionChanges.add(e.getValue()));
+
+ customGrid.getSelectionModel().select("Foo");
+ assertEquals("Foo",
+ customGrid.getSelectionModel().getFirstSelectedItem().get());
+ assertEquals(Arrays.asList("Foo"), selectionChanges);
+
+ customGrid.switchSelectionModel();
+ assertEquals(Arrays.asList("Foo", null), selectionChanges);
+ }
+
+ @Test
+ public void testGridWithSingleSelection() {
+ Grid<String> gridWithStrings = new Grid<>();
+ gridWithStrings.setItems("Foo", "Bar", "Baz");
+
+ GridSelectionModel<String> model = gridWithStrings.getSelectionModel();
+ Assert.assertFalse(model.isSelected("Foo"));
+
+ model.select("Foo");
+ Assert.assertTrue(model.isSelected("Foo"));
+ Assert.assertEquals(Optional.of("Foo"), model.getFirstSelectedItem());
+
+ model.select("Bar");
+ Assert.assertFalse(model.isSelected("Foo"));
+ Assert.assertTrue(model.isSelected("Bar"));
+
+ model.deselect("Bar");
+ Assert.assertFalse(model.isSelected("Bar"));
+ Assert.assertFalse(model.getFirstSelectedItem().isPresent());
+ }
+
+ @Test
+ public void select_isSelected() {
+ selectionModel.select(PERSON_B);
+
+ assertTrue(selectionModel.getSelectedItem().isPresent());
+
+ assertEquals(PERSON_B, selectionModel.getSelectedItem().orElse(null));
+
+ assertFalse(selectionModel.isSelected(PERSON_A));
+ assertTrue(selectionModel.isSelected(PERSON_B));
+ assertFalse(selectionModel.isSelected(PERSON_C));
+
+ assertEquals(Optional.of(PERSON_B), selectionModel.getSelectedItem());
+
+ assertEquals(Arrays.asList(PERSON_B), selectionChanges);
+ }
+
+ @Test
+ public void selectDeselect() {
+
+ selectionModel.select(PERSON_B);
+ selectionModel.deselect(PERSON_B);
+
+ assertFalse(selectionModel.getSelectedItem().isPresent());
+
+ assertFalse(selectionModel.isSelected(PERSON_A));
+ assertFalse(selectionModel.isSelected(PERSON_B));
+ assertFalse(selectionModel.isSelected(PERSON_C));
+
+ assertFalse(selectionModel.getSelectedItem().isPresent());
+
+ assertEquals(Arrays.asList(PERSON_B, null), selectionChanges);
+ }
+
+ @Test
+ public void reselect() {
+ selectionModel.select(PERSON_B);
+ selectionModel.select(PERSON_C);
+
+ assertEquals(PERSON_C, selectionModel.getSelectedItem().orElse(null));
+
+ assertFalse(selectionModel.isSelected(PERSON_A));
+ assertFalse(selectionModel.isSelected(PERSON_B));
+ assertTrue(selectionModel.isSelected(PERSON_C));
+
+ assertEquals(Optional.of(PERSON_C), selectionModel.getSelectedItem());
+
+ assertEquals(Arrays.asList(PERSON_B, PERSON_C), selectionChanges);
+ }
+
+ @Test
+ public void selectTwice() {
+
+ selectionModel.select(PERSON_C);
+ selectionModel.select(PERSON_C);
+
+ assertEquals(PERSON_C, selectionModel.getSelectedItem().orElse(null));
+
+ assertFalse(selectionModel.isSelected(PERSON_A));
+ assertFalse(selectionModel.isSelected(PERSON_B));
+ assertTrue(selectionModel.isSelected(PERSON_C));
+
+ assertEquals(Optional.of(PERSON_C), selectionModel.getSelectedItem());
+
+ assertEquals(Arrays.asList(PERSON_C), selectionChanges);
+ }
+
+ @Test
+ public void deselectTwice() {
+
+ selectionModel.select(PERSON_C);
+ selectionModel.deselect(PERSON_C);
+ selectionModel.deselect(PERSON_C);
+
+ assertFalse(selectionModel.getSelectedItem().isPresent());
+
+ assertFalse(selectionModel.isSelected(PERSON_A));
+ assertFalse(selectionModel.isSelected(PERSON_B));
+ assertFalse(selectionModel.isSelected(PERSON_C));
+
+ assertFalse(selectionModel.getSelectedItem().isPresent());
+
+ assertEquals(Arrays.asList(PERSON_C, null), selectionChanges);
+ }
+
+ @Test
+ public void getSelectedItem() {
+ selectionModel.setSelectedItem(PERSON_B);
+
+ Assert.assertEquals(PERSON_B, selectionModel.getSelectedItem().get());
+
+ selectionModel.deselect(PERSON_B);
+ Assert.assertFalse(selectionModel.getSelectedItem().isPresent());
+ }
+
+ @Test
+ public void select_deselect_getSelectedItem() {
+ selectionModel.select(PERSON_C);
+
+ Assert.assertEquals(PERSON_C, selectionModel.getSelectedItem().get());
+
+ selectionModel.deselect(PERSON_C);
+
+ Assert.assertFalse(selectionModel.getSelectedItem().isPresent());
+ }
+
+ @SuppressWarnings({ "serial" })
+ @Test
+ public void addValueChangeListener() {
+ AtomicReference<SingleSelectionListener<String>> selectionListener = new AtomicReference<>();
+ Registration registration = Mockito.mock(Registration.class);
+ Grid<String> grid = new Grid<>();
+ grid.setItems("foo", "bar");
+ String value = "foo";
+ SingleSelectionModel<String> select = new SingleSelectionModel<String>(
+ grid) {
+ @Override
+ public Registration addSelectionChangeListener(
+ SingleSelectionListener<String> listener) {
+ selectionListener.set(listener);
+ return registration;
+ }
+
+ @Override
+ public Optional<String> getSelectedItem() {
+ return Optional.of(value);
+ }
+ };
+
+ AtomicReference<ValueChangeEvent<?>> event = new AtomicReference<>();
+ Registration actualRegistration = select
+ .addSelectionChangeListener(evt -> {
+ Assert.assertNull(event.get());
+ event.set(evt);
+ });
+ Assert.assertSame(registration, actualRegistration);
+
+ selectionListener.get().accept(new SingleSelectionEvent<>(grid,
+ select.asSingleSelect(), true));
+
+ Assert.assertEquals(grid, event.get().getComponent());
+ Assert.assertEquals(value, event.get().getValue());
+ Assert.assertTrue(event.get().isUserOriginated());
+ }
+
+}
diff --git a/server/src/test/java/com/vaadin/ui/AbstractSingleSelectTest.java b/server/src/test/java/com/vaadin/ui/AbstractSingleSelectTest.java
index 47f5fbc81d..b429afb600 100644
--- a/server/src/test/java/com/vaadin/ui/AbstractSingleSelectTest.java
+++ b/server/src/test/java/com/vaadin/ui/AbstractSingleSelectTest.java
@@ -1,12 +1,12 @@
/*
* Copyright 2000-2014 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
@@ -21,10 +21,8 @@ import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
-import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Assert;
@@ -33,7 +31,7 @@ import org.junit.Test;
import org.mockito.Mockito;
import com.vaadin.data.HasValue.ValueChangeEvent;
-import com.vaadin.event.selection.SingleSelectionChangeEvent;
+import com.vaadin.event.selection.SingleSelectionEvent;
import com.vaadin.event.selection.SingleSelectionListener;
import com.vaadin.server.data.datasource.bov.Person;
import com.vaadin.shared.Registration;
@@ -56,7 +54,8 @@ public class AbstractSingleSelectTest {
listing = new PersonListing();
listing.setItems(PERSON_A, PERSON_B, PERSON_C);
selectionChanges = new ArrayList<>();
- listing.addSelectionListener(e -> selectionChanges.add(e.getValue()));
+ listing.addSelectionChangeListener(
+ e -> selectionChanges.add(e.getValue()));
}
public static final Person PERSON_C = new Person("c", 3);
@@ -69,7 +68,7 @@ public class AbstractSingleSelectTest {
@Test
public void select() {
- listing.select(PERSON_B);
+ listing.setValue(PERSON_B);
assertTrue(listing.getSelectedItem().isPresent());
@@ -87,8 +86,8 @@ public class AbstractSingleSelectTest {
@Test
public void selectDeselect() {
- listing.select(PERSON_B);
- listing.deselect(PERSON_B);
+ listing.setValue(PERSON_B);
+ listing.setValue(null);
assertFalse(listing.getSelectedItem().isPresent());
@@ -104,8 +103,8 @@ public class AbstractSingleSelectTest {
@Test
public void reselect() {
- listing.select(PERSON_B);
- listing.select(PERSON_C);
+ listing.setValue(PERSON_B);
+ listing.setValue(PERSON_C);
assertEquals(PERSON_C, listing.getSelectedItem().orElse(null));
@@ -119,27 +118,10 @@ public class AbstractSingleSelectTest {
}
@Test
- public void deselectNoOp() {
-
- listing.select(PERSON_C);
- listing.deselect(PERSON_B);
-
- assertEquals(PERSON_C, listing.getSelectedItem().orElse(null));
-
- assertFalse(listing.isSelected(PERSON_A));
- assertFalse(listing.isSelected(PERSON_B));
- assertTrue(listing.isSelected(PERSON_C));
-
- assertEquals(Optional.of(PERSON_C), listing.getSelectedItem());
-
- assertEquals(Arrays.asList(PERSON_C), selectionChanges);
- }
-
- @Test
public void selectTwice() {
- listing.select(PERSON_C);
- listing.select(PERSON_C);
+ listing.setValue(PERSON_C);
+ listing.setValue(PERSON_C);
assertEquals(PERSON_C, listing.getSelectedItem().orElse(null));
@@ -155,9 +137,9 @@ public class AbstractSingleSelectTest {
@Test
public void deselectTwice() {
- listing.select(PERSON_C);
- listing.deselect(PERSON_C);
- listing.deselect(PERSON_C);
+ listing.setValue(PERSON_C);
+ listing.setValue(null);
+ listing.setValue(null);
assertFalse(listing.getSelectedItem().isPresent());
@@ -176,7 +158,7 @@ public class AbstractSingleSelectTest {
Assert.assertEquals(PERSON_B, listing.getValue());
- listing.deselect(PERSON_B);
+ listing.setValue(null);
Assert.assertNull(listing.getValue());
}
@@ -220,7 +202,7 @@ public class AbstractSingleSelectTest {
Mockito.verify(select).setSelectedItem(null);
}
- @SuppressWarnings({ "unchecked", "serial" })
+ @SuppressWarnings("serial")
@Test
public void addValueChangeListener() {
AtomicReference<SingleSelectionListener<String>> selectionListener = new AtomicReference<>();
@@ -228,7 +210,7 @@ public class AbstractSingleSelectTest {
String value = "foo";
AbstractSingleSelect<String> select = new AbstractSingleSelect<String>() {
@Override
- public Registration addSelectionListener(
+ public Registration addSelectionChangeListener(
SingleSelectionListener<String> listener) {
selectionListener.set(listener);
return registration;
@@ -248,32 +230,11 @@ public class AbstractSingleSelectTest {
Assert.assertSame(registration, actualRegistration);
selectionListener.get()
- .accept(new SingleSelectionChangeEvent<>(select, true));
+ .accept(new SingleSelectionEvent<>(select, true));
Assert.assertEquals(select, event.get().getComponent());
Assert.assertEquals(value, event.get().getValue());
Assert.assertTrue(event.get().isUserOriginated());
}
- @Test
- @SuppressWarnings({ "unchecked", "rawtypes" })
- public void setValue_isDelegatedToDeselectAndUpdateSelection() {
- AbstractMultiSelect<String> select = Mockito
- .mock(AbstractMultiSelect.class);
-
- Set set = new LinkedHashSet<>();
- set.add("foo1");
- set.add("foo");
- Set selected = new LinkedHashSet<>();
- selected.add("bar1");
- selected.add("bar");
- selected.add("bar2");
- Mockito.when(select.getSelectedItems()).thenReturn(selected);
- Mockito.doCallRealMethod().when(select).setValue(Mockito.anySet());
-
- select.setValue(set);
-
- 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 ea1cf39351..ec48a74799 100644
--- a/server/src/test/java/com/vaadin/ui/RadioButtonGroupTest.java
+++ b/server/src/test/java/com/vaadin/ui/RadioButtonGroupTest.java
@@ -42,16 +42,16 @@ public class RadioButtonGroupTest {
public void apiSelectionChange_notUserOriginated() {
AtomicInteger listenerCount = new AtomicInteger(0);
- radioButtonGroup.addSelectionListener(event -> {
+ radioButtonGroup.addSelectionChangeListener(event -> {
listenerCount.incrementAndGet();
Assert.assertFalse(event.isUserOriginated());
});
- radioButtonGroup.select("First");
- radioButtonGroup.select("Second");
+ radioButtonGroup.setValue("First");
+ radioButtonGroup.setValue("Second");
- radioButtonGroup.deselect("Second");
- radioButtonGroup.deselect("Second");
+ radioButtonGroup.setValue(null);
+ radioButtonGroup.setValue(null);
Assert.assertEquals(3, listenerCount.get());
}
@@ -60,7 +60,7 @@ public class RadioButtonGroupTest {
public void rpcSelectionChange_userOriginated() {
AtomicInteger listenerCount = new AtomicInteger(0);
- radioButtonGroup.addSelectionListener(event -> {
+ radioButtonGroup.addSelectionChangeListener(event -> {
listenerCount.incrementAndGet();
Assert.assertTrue(event.isUserOriginated());
});