import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.Set;
import java.util.stream.Collectors;
import com.google.gwt.dom.client.Element;
import com.vaadin.client.connectors.AbstractListingConnector;
import com.vaadin.client.connectors.grid.ColumnConnector.CustomColumn;
import com.vaadin.client.data.DataSource;
-import com.vaadin.client.data.SelectionModel;
import com.vaadin.client.ui.SimpleManagedLayout;
import com.vaadin.client.widget.grid.CellReference;
import com.vaadin.client.widget.grid.EventCellReference;
import com.vaadin.client.widgets.Grid.HeaderCell;
import com.vaadin.client.widgets.Grid.HeaderRow;
import com.vaadin.shared.MouseEventDetails;
-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.Connect;
import com.vaadin.shared.ui.grid.GridConstants;
/* Item click events */
getWidget().addBodyClickHandler(itemClickHandler);
getWidget().addBodyDoubleClickHandler(itemClickHandler);
- getWidget().setSelectionModel(new SelectionModel<JsonObject>() {
-
- @Override
- public void select(JsonObject item) {
- getRpcProxy(SelectionServerRpc.class)
- .select(item.getString(DataCommunicatorConstants.KEY));
- }
-
- @Override
- public void deselect(JsonObject item) {
- getRpcProxy(SelectionServerRpc.class).deselect(
- item.getString(DataCommunicatorConstants.KEY));
- }
-
- @Override
- public Set<JsonObject> getSelectedItems() {
- throw new UnsupportedOperationException(
- "Selected item not known on the client side");
- }
-
- @Override
- public boolean isSelected(JsonObject item) {
- return item.hasKey(DataCommunicatorConstants.SELECTED)
- && item.getBoolean(DataCommunicatorConstants.SELECTED);
- }
-
- });
layout();
}
--- /dev/null
+/*
+ * 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.client.connectors.grid;
+
+import java.util.Set;
+
+import com.vaadin.client.ServerConnector;
+import com.vaadin.client.data.SelectionModel;
+import com.vaadin.client.extensions.AbstractExtensionConnector;
+import com.vaadin.shared.data.DataCommunicatorConstants;
+import com.vaadin.shared.data.selection.SelectionServerRpc;
+import com.vaadin.shared.ui.Connect;
+
+import elemental.json.JsonObject;
+
+/**
+ * Client side connector for grid single selection model.
+ *
+ * @author Vaadin Ltd.
+ *
+ * @since 8.0
+ */
+@Connect(com.vaadin.ui.components.grid.SingleSelectionModel.class)
+public class SingleSelectionModelConnector extends AbstractExtensionConnector {
+
+ @Override
+ protected void extend(ServerConnector target) {
+ getParent().getWidget()
+ .setSelectionModel(new SelectionModel<JsonObject>() {
+
+ @Override
+ public void select(JsonObject item) {
+ getRpcProxy(SelectionServerRpc.class).select(
+ item.getString(DataCommunicatorConstants.KEY));
+ }
+
+ @Override
+ public void deselect(JsonObject item) {
+ getRpcProxy(SelectionServerRpc.class).deselect(
+ item.getString(DataCommunicatorConstants.KEY));
+ }
+
+ @Override
+ public Set<JsonObject> getSelectedItems() {
+ throw new UnsupportedOperationException(
+ "Selected item not known on the client side");
+ }
+
+ @Override
+ public boolean isSelected(JsonObject item) {
+ return SelectionModel.isItemSelected(item);
+ }
+
+ });
+ }
+
+ @Override
+ public GridConnector getParent() {
+ return (GridConnector) super.getParent();
+ }
+
+}
+++ /dev/null
-/*
- * 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.client.connectors.selection;
-
-import com.vaadin.client.ServerConnector;
-import com.vaadin.client.connectors.AbstractListingConnector;
-import com.vaadin.client.extensions.AbstractExtensionConnector;
-import com.vaadin.shared.data.DataCommunicatorConstants;
-
-import elemental.json.JsonObject;
-
-/**
- * The client-side connector for selection extensions.
- *
- * @author Vaadin Ltd.
- *
- * @since 8.0
- */
-public abstract class AbstractSelectionConnector
- extends AbstractExtensionConnector {
-
- @Override
- @SuppressWarnings("unchecked")
- protected void extend(ServerConnector target) {
- if (!(target instanceof AbstractListingConnector)) {
- throw new IllegalArgumentException(
- "Cannot extend a connector that is not an "
- + AbstractListingConnector.class.getSimpleName());
- }
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public AbstractListingConnector getParent() {
- return (AbstractListingConnector) super.getParent();
- }
-
- /**
- * Gets the selected state from a given json object. This is a helper method
- * for selection model connectors.
- *
- * @param item
- * a json object
- * @return {@code true} if the json object is marked as selected;
- * {@code false} if not
- */
- public static boolean isItemSelected(JsonObject item) {
- return item.hasKey(DataCommunicatorConstants.SELECTED)
- && item.getBoolean(DataCommunicatorConstants.SELECTED);
- }
-
- /**
- * Gets the item key from given json object. This is a helper method for
- * selection model connectors.
- *
- * @param item
- * a json object
- * @return item key; {@code null} if there is no key
- */
- public static String getKey(JsonObject item) {
- if (item.hasKey(DataCommunicatorConstants.KEY)) {
- return item.getString(DataCommunicatorConstants.KEY);
- } else {
- return null;
- }
- }
-
-}
import java.util.Set;
+import com.vaadin.shared.data.DataCommunicatorConstants;
+
+import elemental.json.JsonObject;
+
/**
* Models the selection logic of a {@code Grid} component. Determines how items
* can be selected and deselected.
/**
* Selects the given item. If another item was already selected, that item
* is deselected.
- *
+ *
* @param item
* the item to select, not null
*/
/**
* Returns a set of the currently selected items. It is safe to invoke other
* {@code SelectionModel} methods while iterating over the set.
- *
+ *
* @return the items in the current selection, not null
*/
Set<T> getSelectedItems();
default void deselectAll() {
getSelectedItems().forEach(this::deselect);
}
+
+ /**
+ * Gets the selected state from a given grid row json object. This is a
+ * helper method for grid selection models.
+ *
+ * @param item
+ * a json object
+ * @return {@code true} if the json object is marked as selected;
+ * {@code false} if not
+ */
+ public static boolean isItemSelected(JsonObject item) {
+ return item.hasKey(DataCommunicatorConstants.SELECTED)
+ && item.getBoolean(DataCommunicatorConstants.SELECTED);
+ }
+
}
return getSelectedItem().map(Collections::singleton)
.orElse(Collections.emptySet());
}
+
+ @Override
+ default Optional<T> getFirstSelectedItem() {
+ return getSelectedItem();
+ }
}
/**
* 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();
+ }
}
/**
*/
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.
+++ /dev/null
-/*
- * 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) {
- }
-}
+++ /dev/null
-/*
- * 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.event.selection;
-
-import java.util.Optional;
-
-import com.vaadin.data.HasValue.ValueChangeEvent;
-import com.vaadin.ui.AbstractListing;
-import com.vaadin.ui.AbstractSingleSelect;
-
-/**
- * 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>
- 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,
- boolean userOriginated) {
- super(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()
- */
- public Optional<T> getSelectedItem() {
- return Optional.ofNullable(getValue());
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public AbstractListing<T> getComponent() {
- return (AbstractListing<T>) super.getComponent();
- }
-
- @Override
- public Optional<T> getFirstSelected() {
- return getSelectedItem();
- }
-}
--- /dev/null
+/*
+ * 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.event.selection;
+
+import java.util.Optional;
+
+import com.vaadin.data.HasValue.ValueChangeEvent;
+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 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 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()
+ */
+ public Optional<T> getSelectedItem() {
+ return Optional.ofNullable(getValue());
+ }
+
+ /**
+ * The single select on which the Event initially occurred.
+ *
+ * @return The single select on which the Event initially occurred.
+ */
+ @Override
+ public SingleSelect<T> getSource() {
+ return (SingleSelect<T>) super.getSource();
+ }
+
+ @Override
+ public Optional<T> getFirstSelected() {
+ return getSelectedItem();
+ }
+}
* @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);
}
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;
@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.
* 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);
}
/**
@Override
public Registration addValueChangeListener(
HasValue.ValueChangeListener<T> listener) {
- return addSelectionListener(event -> listener.accept(
+ return addSelectionChangeListener(event -> listener.accept(
new ValueChangeEvent<>(this, event.isUserOriginated())));
}
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.
}
doSetSelectedKey(key);
- fireEvent(new SingleSelectionChangeEvent<>(AbstractSingleSelect.this,
+ fireEvent(new SingleSelectionEvent<>(AbstractSingleSelect.this,
true));
}
}
doSetSelectedKey(key);
- fireEvent(new SingleSelectionChangeEvent<>(AbstractSingleSelect.this,
+ fireEvent(new SingleSelectionEvent<>(AbstractSingleSelect.this,
false));
}
@Override
public Registration addValueChangeListener(
HasValue.ValueChangeListener<T> listener) {
- return addSelectionListener(event -> {
+ return addSelectionChangeListener(event -> {
listener.accept(new ValueChangeEvent<>(event.getComponent(), this,
event.isUserOriginated()));
});
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;
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;
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;
* @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(
void columnReorder(ColumnReorderEvent event);
}
+ /**
+ * 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.
*/
.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();
}
}
}
- 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.
*/
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);
*
* @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;
}
range.setWidth("100%");
range.addValueChangeListener(this::valueChange);
- range.select(ColorRange.ALL);
+ range.setValue(ColorRange.ALL);
layout.addComponent(range);
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(
// 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));
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(
--- /dev/null
+/*
+ * 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
/*
* 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
public void bound_setSelection_beanValueUpdated() {
bindSex();
- select.select(Sex.MALE);
+ select.setValue(Sex.MALE);
assertSame(Sex.MALE, item.getSex());
}
item.setSex(Sex.MALE);
bindSex();
- select.deselect(Sex.MALE);
+ select.setValue(null);
assertNull(item.getSex());
}
bindSex();
binder.removeBean();
- select.select(Sex.FEMALE);
+ select.setValue(Sex.FEMALE);
assertSame(Sex.UNKNOWN, item.getSex());
}
--- /dev/null
+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);
+ }
+}
@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"));
+++ /dev/null
-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());
- }
-
-}
--- /dev/null
+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());
+ }
+
+}
/*
* 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
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;
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;
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);
@Test
public void select() {
- listing.select(PERSON_B);
+ listing.setValue(PERSON_B);
assertTrue(listing.getSelectedItem().isPresent());
@Test
public void selectDeselect() {
- listing.select(PERSON_B);
- listing.deselect(PERSON_B);
+ listing.setValue(PERSON_B);
+ listing.setValue(null);
assertFalse(listing.getSelectedItem().isPresent());
@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));
assertEquals(Arrays.asList(PERSON_B, PERSON_C), selectionChanges);
}
- @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));
@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());
Assert.assertEquals(PERSON_B, listing.getValue());
- listing.deselect(PERSON_B);
+ listing.setValue(null);
Assert.assertNull(listing.getValue());
}
Mockito.verify(select).setSelectedItem(null);
}
- @SuppressWarnings({ "unchecked", "serial" })
+ @SuppressWarnings("serial")
@Test
public void addValueChangeListener() {
AtomicReference<SingleSelectionListener<String>> selectionListener = new AtomicReference<>();
String value = "foo";
AbstractSingleSelect<String> select = new AbstractSingleSelect<String>() {
@Override
- public Registration addSelectionListener(
+ public Registration addSelectionChangeListener(
SingleSelectionListener<String> listener) {
selectionListener.set(listener);
return registration;
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);
- }
-
}
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());
}
public void rpcSelectionChange_userOriginated() {
AtomicInteger listenerCount = new AtomicInteger(0);
- radioButtonGroup.addSelectionListener(event -> {
+ radioButtonGroup.addSelectionChangeListener(event -> {
listenerCount.incrementAndGet();
Assert.assertTrue(event.isUserOriginated());
});
protected void createListenerMenu() {
createListenerAction("Selection listener", "Listeners", c -> c
- .addSelectionListener(e -> log("Selected: " + e.getValue())));
+ .addSelectionChangeListener(e -> log("Selected: " + e.getValue())));
}
protected void createSelectionMenu() {
createSelectAction("Select", "Selection", options, "None",
(component, selected, data) -> {
- if (selected != null) {
- component.select(selected);
- } else {
- component.getSelectedItem()
- .ifPresent(component::deselect);
- }
+ component.setValue(selected);
});
}
comboBox.setNewItemHandler(text -> {
items.add(text);
comboBox.setItems(items);
- comboBox.select(text);
+ comboBox.setValue(text);
label.setValue(String.valueOf(items.size()));
});
import com.vaadin.ui.Panel;
import com.vaadin.ui.StyleGenerator;
import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.components.grid.SingleSelectionModel;
import com.vaadin.ui.renderers.DateRenderer;
import com.vaadin.ui.renderers.HtmlRenderer;
import com.vaadin.ui.renderers.NumberRenderer;
.put("\"Watching\"",
dataObj -> new Label("You are watching item id "
+ dataObj.getRowNumber() + " ("
- + (watchingCount++) + ")"));
+ + watchingCount++ + ")"));
persistingDetails = new PersistingDetailsGenerator();
generators.put("Persisting", persistingDetails);
}
grid.addColumn(data -> data.getSmallRandom() / 5d,
new ProgressBarRenderer()).setCaption(COLUMN_CAPTIONS[7]);
- grid.addSelectionListener(e -> log("Selected: " + e.getValue()));
+ ((SingleSelectionModel<DataObject>) grid.getSelectionModel())
+ .addSelectionChangeListener(e -> log("Selected: " + e.getValue()));
layout.addComponent(createMenu());
layout.addComponent(grid);
protected void setup(VaadinRequest request) {
NativeSelect<String> select = new NativeSelect<>();
select.setItems("Foo", "Bar");
- select.select("Bar");
+ select.setValue("Bar");
addComponent(select);
}
protected void createSelectionMenu() {
createClickAction("Clear selection", selectionCategory,
(component, item, data) -> component.getSelectedItem()
- .ifPresent(component::deselect),
+ .ifPresent(value -> component.setValue(null)),
"");
Command<RadioButtonGroup<Object>, String> toggleSelection = (component,
private void toggleSelection(String item) {
if (getComponent().isSelected(item)) {
- getComponent().deselect(item);
+ getComponent().setValue(null);
} else {
- getComponent().select(item);
+ getComponent().setValue(item);
}
}
protected void createListenerMenu() {
createListenerAction("Selection listener", "Listeners",
- c -> c.addSelectionListener(
+ c -> c.addSelectionChangeListener(
e -> log("Selected: " + e.getSelectedItem())));
}
@Override
public Stream<String> fetch(Query query) {
- log("Backend request #" + (count++));
+ log("Backend request #" + count++);
return super.fetch(query);
}
}
}
@Override
- public void select(String item) {
+ public void setValue(String item) {
if (selected != null) {
getDataCommunicator().refresh(selected);
}
}
}
- @Override
- public void deselect(String item) {
- if (item == selected) {
- select(null);
- }
- }
}
@Override
items.add("Foo " + i);
}
dummy.setDataSource(new LoggingDataSource(items));
- dummy.select("Foo 200");
+ dummy.setValue("Foo 200");
HorizontalLayout controls = new HorizontalLayout();
addComponent(controls);
controls.addComponent(new Button("Select Foo 20", e -> {
- dummy.select("Foo " + 20);
+ dummy.setValue("Foo " + 20);
}));
controls.addComponent(new Button("Reset data source", e -> {
dummy.setDataSource(new LoggingDataSource(items));