summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenis <denis@vaadin.com>2016-12-06 21:38:08 +0200
committerPekka Hyvönen <pekka@vaadin.com>2016-12-06 21:38:08 +0200
commit620b2ba314f0f88760803a084cc38e47b57632d3 (patch)
tree5fcb2d08009e874cecf08669a74f041b0622a741
parent77fd42425b59805b5c30dcafc3512eecaa78e24c (diff)
downloadvaadin-framework-620b2ba314f0f88760803a084cc38e47b57632d3.tar.gz
vaadin-framework-620b2ba314f0f88760803a084cc38e47b57632d3.zip
Add read-only support for single and multi select views for Grid. (#84)
* Add read-only support for single and multi select views for Grid. Fixes vaadin/framework8-issues#516
-rw-r--r--client/src/main/java/com/vaadin/client/connectors/grid/AbstractSelectionModelConnector.java7
-rw-r--r--client/src/main/java/com/vaadin/client/connectors/grid/MultiSelectionModelConnector.java15
-rw-r--r--client/src/main/java/com/vaadin/client/connectors/grid/NoSelectionModelConnector.java22
-rw-r--r--client/src/main/java/com/vaadin/client/connectors/grid/SingleSelectionModelConnector.java15
-rw-r--r--client/src/main/java/com/vaadin/client/widget/grid/events/GridSelectionAllowedEvent.java63
-rw-r--r--client/src/main/java/com/vaadin/client/widget/grid/events/GridSelectionAllowedHandler.java39
-rw-r--r--client/src/main/java/com/vaadin/client/widget/grid/selection/ClickSelectHandler.java3
-rw-r--r--client/src/main/java/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java28
-rw-r--r--client/src/main/java/com/vaadin/client/widget/grid/selection/SelectionModel.java52
-rw-r--r--client/src/main/java/com/vaadin/client/widgets/Grid.java113
-rw-r--r--server/src/main/java/com/vaadin/ui/components/grid/MultiSelectionModelImpl.java17
-rw-r--r--server/src/main/java/com/vaadin/ui/components/grid/SingleSelectionModelImpl.java15
-rw-r--r--server/src/test/java/com/vaadin/tests/components/grid/GridMultiSelectionModelTest.java22
-rw-r--r--server/src/test/java/com/vaadin/tests/components/grid/GridSingleSelectionModelTest.java19
-rw-r--r--shared/src/main/java/com/vaadin/shared/ui/grid/AbstractSelectionModelState.java5
-rw-r--r--uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java31
-rw-r--r--uitest/src/test/java/com/vaadin/tests/components/grid/GridSelectionTest.java157
17 files changed, 524 insertions, 99 deletions
diff --git a/client/src/main/java/com/vaadin/client/connectors/grid/AbstractSelectionModelConnector.java b/client/src/main/java/com/vaadin/client/connectors/grid/AbstractSelectionModelConnector.java
index 5f705cb237..114bc313d6 100644
--- a/client/src/main/java/com/vaadin/client/connectors/grid/AbstractSelectionModelConnector.java
+++ b/client/src/main/java/com/vaadin/client/connectors/grid/AbstractSelectionModelConnector.java
@@ -16,6 +16,7 @@
package com.vaadin.client.connectors.grid;
import com.vaadin.client.ServerConnector;
+import com.vaadin.client.annotations.OnStateChange;
import com.vaadin.client.extensions.AbstractExtensionConnector;
import com.vaadin.client.widget.grid.selection.SelectionModel;
import com.vaadin.client.widgets.Grid;
@@ -61,6 +62,12 @@ public abstract class AbstractSelectionModelConnector
return getParent().getWidget();
}
+ @OnStateChange("selectionAllowed")
+ private void onSelectionAllowedChange() {
+ getGrid().getSelectionModel()
+ .setSelectionAllowed(getState().selectionAllowed);
+ }
+
@Override
public AbstractSelectionModelState getState() {
return (AbstractSelectionModelState) super.getState();
diff --git a/client/src/main/java/com/vaadin/client/connectors/grid/MultiSelectionModelConnector.java b/client/src/main/java/com/vaadin/client/connectors/grid/MultiSelectionModelConnector.java
index 8ad86f1541..83008b5a88 100644
--- a/client/src/main/java/com/vaadin/client/connectors/grid/MultiSelectionModelConnector.java
+++ b/client/src/main/java/com/vaadin/client/connectors/grid/MultiSelectionModelConnector.java
@@ -22,6 +22,7 @@ import com.vaadin.client.annotations.OnStateChange;
import com.vaadin.client.data.DataSource;
import com.vaadin.client.data.DataSource.RowHandle;
import com.vaadin.client.renderers.Renderer;
+import com.vaadin.client.widget.grid.events.GridSelectionAllowedEvent;
import com.vaadin.client.widget.grid.events.SelectAllEvent;
import com.vaadin.client.widget.grid.selection.MultiSelectionRenderer;
import com.vaadin.client.widget.grid.selection.SelectionModel;
@@ -64,6 +65,8 @@ public class MultiSelectionModelConnector
protected class MultiSelectionModel implements SelectionModel<JsonObject>,
SelectionModelWithSelectionColumn {
+ private boolean isSelectionAllowed = true;
+
@Override
public Renderer<Boolean> getRenderer() {
// this method is only called once when the selection model is set
@@ -106,6 +109,18 @@ public class MultiSelectionModelConnector
return MultiSelectionModelConnector.this.isSelected(item);
}
+ @Override
+ public void setSelectionAllowed(boolean selectionAllowed) {
+ isSelectionAllowed = selectionAllowed;
+ getGrid()
+ .fireEvent(new GridSelectionAllowedEvent(selectionAllowed));
+ }
+
+ @Override
+ public boolean isSelectionAllowed() {
+ return isSelectionAllowed;
+ }
+
}
@Override
diff --git a/client/src/main/java/com/vaadin/client/connectors/grid/NoSelectionModelConnector.java b/client/src/main/java/com/vaadin/client/connectors/grid/NoSelectionModelConnector.java
index 383fae2882..bc21b5990e 100644
--- a/client/src/main/java/com/vaadin/client/connectors/grid/NoSelectionModelConnector.java
+++ b/client/src/main/java/com/vaadin/client/connectors/grid/NoSelectionModelConnector.java
@@ -20,8 +20,6 @@ import com.vaadin.client.extensions.AbstractExtensionConnector;
import com.vaadin.client.widget.grid.selection.SelectionModel;
import com.vaadin.shared.ui.Connect;
-import elemental.json.JsonObject;
-
/**
* Connector for grids selection model that doesn't allow selecting anything.
*
@@ -37,25 +35,7 @@ public class NoSelectionModelConnector extends AbstractExtensionConnector {
assert target instanceof GridConnector : "NoSelectionModelConnector cannot extend anything else than Grid.";
((GridConnector) target).getWidget()
- .setSelectionModel(new SelectionModel<JsonObject>() {
-
- @Override
- public void select(JsonObject item) {
- }
-
- @Override
- public void deselect(JsonObject item) {
- }
-
- @Override
- public boolean isSelected(JsonObject item) {
- return false;
- }
-
- @Override
- public void deselectAll() {
- }
- });
+ .setSelectionModel(new SelectionModel.NoSelectionModel<>());
}
}
diff --git a/client/src/main/java/com/vaadin/client/connectors/grid/SingleSelectionModelConnector.java b/client/src/main/java/com/vaadin/client/connectors/grid/SingleSelectionModelConnector.java
index d18f372a2c..9b1d7cc27a 100644
--- a/client/src/main/java/com/vaadin/client/connectors/grid/SingleSelectionModelConnector.java
+++ b/client/src/main/java/com/vaadin/client/connectors/grid/SingleSelectionModelConnector.java
@@ -15,6 +15,7 @@
*/
package com.vaadin.client.connectors.grid;
+import com.vaadin.client.widget.grid.events.GridSelectionAllowedEvent;
import com.vaadin.client.widget.grid.selection.ClickSelectHandler;
import com.vaadin.client.widget.grid.selection.SelectionModel;
import com.vaadin.shared.data.DataCommunicatorConstants;
@@ -41,6 +42,8 @@ public class SingleSelectionModelConnector
*/
protected class SingleSelectionModel implements SelectionModel<JsonObject> {
+ private boolean isSelectionAllowed = true;
+
@Override
public void select(JsonObject item) {
getRpcProxy(SelectionServerRpc.class)
@@ -62,6 +65,18 @@ public class SingleSelectionModelConnector
public void deselectAll() {
getRpcProxy(SelectionServerRpc.class).select(null);
}
+
+ @Override
+ public void setSelectionAllowed(boolean selectionAllowed) {
+ isSelectionAllowed = selectionAllowed;
+ getGrid()
+ .fireEvent(new GridSelectionAllowedEvent(selectionAllowed));
+ }
+
+ @Override
+ public boolean isSelectionAllowed() {
+ return isSelectionAllowed;
+ }
}
@Override
diff --git a/client/src/main/java/com/vaadin/client/widget/grid/events/GridSelectionAllowedEvent.java b/client/src/main/java/com/vaadin/client/widget/grid/events/GridSelectionAllowedEvent.java
new file mode 100644
index 0000000000..e0aeed8871
--- /dev/null
+++ b/client/src/main/java/com/vaadin/client/widget/grid/events/GridSelectionAllowedEvent.java
@@ -0,0 +1,63 @@
+/*
+ * 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.widget.grid.events;
+
+import com.google.gwt.event.shared.GwtEvent;
+
+/**
+ * A selection allowed event, fired by the Grid when its selection allowed value
+ * changes.
+ *
+ * @since 8.0
+ * @author Vaadin Ltd
+ */
+public class GridSelectionAllowedEvent
+ extends GwtEvent<GridSelectionAllowedHandler> {
+ /**
+ * The type of this event
+ */
+ public static final Type<GridSelectionAllowedHandler> TYPE = new Type<>();
+ private final boolean isSelectionAllowed;
+
+ /**
+ * Creates a new event instance.
+ *
+ * @param selectionAllowed
+ * selection allowed value
+ */
+ public GridSelectionAllowedEvent(boolean selectionAllowed) {
+ isSelectionAllowed = selectionAllowed;
+ }
+
+ @Override
+ public Type<GridSelectionAllowedHandler> getAssociatedType() {
+ return TYPE;
+ }
+
+ /**
+ * Gets selection allowed value.
+ *
+ * @return {@code true} if selection is allowed, {@code false} otherwise
+ */
+ public boolean isSelectionAllowed() {
+ return isSelectionAllowed;
+ }
+
+ @Override
+ protected void dispatch(final GridSelectionAllowedHandler handler) {
+ handler.onSelectionAllowed(this);
+ }
+}
diff --git a/client/src/main/java/com/vaadin/client/widget/grid/events/GridSelectionAllowedHandler.java b/client/src/main/java/com/vaadin/client/widget/grid/events/GridSelectionAllowedHandler.java
new file mode 100644
index 0000000000..23788b329b
--- /dev/null
+++ b/client/src/main/java/com/vaadin/client/widget/grid/events/GridSelectionAllowedHandler.java
@@ -0,0 +1,39 @@
+/*
+ * 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.widget.grid.events;
+
+import com.google.gwt.event.shared.EventHandler;
+
+/**
+ * Handler for a Grid {@link GridSelectionAllowedEvent}, called when the Grid is
+ * becomes allowed for selection or disallowed.
+ *
+ * @see GridSelectionAllowedEvent
+ * @author Vaadin Ltd
+ * @since 8.0
+ *
+ */
+public interface GridSelectionAllowedHandler extends EventHandler {
+
+ /**
+ * Called when Grid selection is allowed value changes.
+ *
+ * @param event
+ * the {@link GridSelectionAllowedEvent} that was fired
+ *
+ */
+ public void onSelectionAllowed(GridSelectionAllowedEvent event);
+}
diff --git a/client/src/main/java/com/vaadin/client/widget/grid/selection/ClickSelectHandler.java b/client/src/main/java/com/vaadin/client/widget/grid/selection/ClickSelectHandler.java
index 7d24fd8488..2f96909f9d 100644
--- a/client/src/main/java/com/vaadin/client/widget/grid/selection/ClickSelectHandler.java
+++ b/client/src/main/java/com/vaadin/client/widget/grid/selection/ClickSelectHandler.java
@@ -36,6 +36,9 @@ public class ClickSelectHandler<T> {
@Override
public void onClick(GridClickEvent event) {
+ if (!grid.getSelectionModel().isSelectionAllowed()) {
+ return;
+ }
T row = (T) event.getTargetCell().getRow();
if (!grid.isSelected(row)) {
grid.select(row);
diff --git a/client/src/main/java/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java b/client/src/main/java/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java
index e1f9ebb18e..14c2210696 100644
--- a/client/src/main/java/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java
+++ b/client/src/main/java/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java
@@ -42,8 +42,9 @@ import com.vaadin.client.WidgetUtil;
import com.vaadin.client.renderers.ClickableRenderer;
import com.vaadin.client.widget.grid.CellReference;
import com.vaadin.client.widget.grid.RendererCellReference;
-import com.vaadin.client.widget.grid.events.GridEnabledEvent;
import com.vaadin.client.widget.grid.events.GridEnabledHandler;
+import com.vaadin.client.widget.grid.events.GridSelectionAllowedEvent;
+import com.vaadin.client.widget.grid.events.GridSelectionAllowedHandler;
import com.vaadin.client.widgets.Grid;
/**
@@ -76,8 +77,9 @@ public class MultiSelectionRenderer<T>
*
* @since 7.5
*/
- private final class CheckBoxEventHandler implements MouseDownHandler,
- TouchStartHandler, ClickHandler, GridEnabledHandler {
+ private final class CheckBoxEventHandler
+ implements MouseDownHandler, TouchStartHandler, ClickHandler,
+ GridEnabledHandler, GridSelectionAllowedHandler {
private final CheckBox checkBox;
/**
@@ -114,7 +116,17 @@ public class MultiSelectionRenderer<T>
@Override
public void onEnabled(boolean enabled) {
- checkBox.setEnabled(enabled);
+ updateEnable();
+ }
+
+ @Override
+ public void onSelectionAllowed(GridSelectionAllowedEvent event) {
+ updateEnable();
+ }
+
+ private void updateEnable() {
+ checkBox.setEnabled(grid.isEnabled()
+ && grid.getSelectionModel().isSelectionAllowed());
}
}
@@ -607,9 +619,8 @@ public class MultiSelectionRenderer<T>
checkBox.addMouseDownHandler(handler);
checkBox.addTouchStartHandler(handler);
checkBox.addClickHandler(handler);
- grid.addHandler(handler, GridEnabledEvent.TYPE);
-
- checkBox.setEnabled(grid.isEnabled());
+ grid.addEnabledHandler(handler);
+ grid.addSelectionAllowedHandler(handler);
return checkBox;
}
@@ -618,7 +629,8 @@ public class MultiSelectionRenderer<T>
public void render(final RendererCellReference cell, final Boolean data,
CheckBox checkBox) {
checkBox.setValue(data, false);
- checkBox.setEnabled(grid.isEnabled() && !grid.isEditorActive());
+ checkBox.setEnabled(grid.isEnabled() && !grid.isEditorActive()
+ && grid.getSelectionModel().isSelectionAllowed());
checkBox.getElement().setPropertyInt(LOGICAL_ROW_PROPERTY_INT,
cell.getRowIndex());
}
diff --git a/client/src/main/java/com/vaadin/client/widget/grid/selection/SelectionModel.java b/client/src/main/java/com/vaadin/client/widget/grid/selection/SelectionModel.java
index 27e099ad46..28499621df 100644
--- a/client/src/main/java/com/vaadin/client/widget/grid/selection/SelectionModel.java
+++ b/client/src/main/java/com/vaadin/client/widget/grid/selection/SelectionModel.java
@@ -31,6 +31,35 @@ import elemental.json.JsonObject;
*/
public interface SelectionModel<T> {
+ public static class NoSelectionModel<T> implements SelectionModel<T> {
+
+ @Override
+ public void select(T item) {
+ }
+
+ @Override
+ public void deselect(T item) {
+ }
+
+ @Override
+ public boolean isSelected(T item) {
+ return false;
+ }
+
+ @Override
+ public void deselectAll() {
+ }
+
+ @Override
+ public void setSelectionAllowed(boolean selectionAllowed) {
+ }
+
+ @Override
+ public boolean isSelectionAllowed() {
+ return false;
+ }
+ }
+
/**
* Selects the given item. If another item was already selected, that item
* is deselected.
@@ -64,6 +93,29 @@ public interface SelectionModel<T> {
void deselectAll();
/**
+ * Sets whether the user is allowed to change the selection.
+ * <p>
+ * The check is done only for the client side actions. It doesn't affect
+ * selection requests sent from the server side.
+ *
+ * @param selectionAllowed
+ * <code>true</code> if the user is allowed to change the
+ * selection, <code>false</code> otherwise
+ */
+ void setSelectionAllowed(boolean selectionAllowed);
+
+ /**
+ * Checks if the user is allowed to change the selection.
+ * <p>
+ * The check is done only for the client side actions. It doesn't affect
+ * selection requests sent from the server side.
+ *
+ * @return <code>true</code> if the user is allowed to change the selection,
+ * <code>false</code> otherwise
+ */
+ boolean isSelectionAllowed();
+
+ /**
* Gets the selected state from a given grid row json object. This is a
* helper method for grid selection models.
*
diff --git a/client/src/main/java/com/vaadin/client/widgets/Grid.java b/client/src/main/java/com/vaadin/client/widgets/Grid.java
index afed21b045..368ad8693b 100644
--- a/client/src/main/java/com/vaadin/client/widgets/Grid.java
+++ b/client/src/main/java/com/vaadin/client/widgets/Grid.java
@@ -145,6 +145,8 @@ import com.vaadin.client.widget.grid.events.GridEnabledHandler;
import com.vaadin.client.widget.grid.events.GridKeyDownEvent;
import com.vaadin.client.widget.grid.events.GridKeyPressEvent;
import com.vaadin.client.widget.grid.events.GridKeyUpEvent;
+import com.vaadin.client.widget.grid.events.GridSelectionAllowedEvent;
+import com.vaadin.client.widget.grid.events.GridSelectionAllowedHandler;
import com.vaadin.client.widget.grid.events.HeaderClickHandler;
import com.vaadin.client.widget.grid.events.HeaderDoubleClickHandler;
import com.vaadin.client.widget.grid.events.HeaderKeyDownHandler;
@@ -1870,15 +1872,12 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
grid.isSelected(pinnedRowHandle.getRow()));
checkBox.sinkEvents(Event.ONCLICK);
- checkBox.addClickHandler(new ClickHandler() {
- @Override
- public void onClick(ClickEvent event) {
- T row = pinnedRowHandle.getRow();
- if (grid.isSelected(row)) {
- grid.deselect(row);
- } else {
- grid.select(row);
- }
+ checkBox.addClickHandler(event -> {
+ T row = pinnedRowHandle.getRow();
+ if (grid.isSelected(row)) {
+ grid.deselect(row);
+ } else {
+ grid.select(row);
}
});
grid.attachWidget(checkBox, cell);
@@ -2832,7 +2831,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
}
public final class SelectionColumn extends Column<Boolean, T>
- implements GridEnabledHandler {
+ implements GridEnabledHandler, GridSelectionAllowedHandler {
private boolean initDone = false;
private boolean selected = false;
@@ -2844,6 +2843,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
super(selectColumnRenderer);
addEnabledHandler(this);
+ addSelectionAllowedHandler(this);
}
void initDone() {
@@ -2851,6 +2851,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
setEditable(false);
setResizable(false);
+ updateEnable();
initDone = true;
}
@@ -2951,23 +2952,9 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
return this;
}
- /**
- * Sets whether the selection column is enabled.
- *
- * @since 7.7
- * @param enabled
- * <code>true</code> to enable the column, <code>false</code>
- * to disable it.
- */
- public void setEnabled(boolean enabled) {
- if (selectAllCheckBox != null) {
- selectAllCheckBox.setEnabled(enabled);
- }
- }
-
@Override
public void onEnabled(boolean enabled) {
- setEnabled(enabled);
+ updateEnable();
}
/**
@@ -3024,19 +3011,30 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
}
}
- private void onHeaderClickEvent(GridClickEvent event) {
- CellReference<?> targetCell = event.getTargetCell();
- int defaultRowIndex = getHeader().getRows()
- .indexOf(getDefaultHeaderRow());
+ private void updateEnable() {
+ if (selectAllCheckBox != null) {
+ selectAllCheckBox.setEnabled(isEnabled()
+ && getSelectionModel().isSelectionAllowed());
+ }
+ }
- if (targetCell.getColumnIndex() == 0
- && targetCell.getRowIndex() == defaultRowIndex) {
- selectAllCheckBox.setValue(!selectAllCheckBox.getValue(), true);
+ private void onHeaderClickEvent(GridClickEvent event) {
+ if (selectAllCheckBox.isEnabled()) {
+ CellReference<?> targetCell = event.getTargetCell();
+ int defaultRowIndex = getHeader().getRows()
+ .indexOf(getDefaultHeaderRow());
+
+ if (targetCell.getColumnIndex() == 0
+ && targetCell.getRowIndex() == defaultRowIndex) {
+ selectAllCheckBox.setValue(!selectAllCheckBox.getValue(),
+ true);
+ }
}
}
private void onHeaderKeyUpEvent(GridKeyUpEvent event) {
- if (event.getNativeKeyCode() != KeyCodes.KEY_SPACE) {
+ if (event.getNativeKeyCode() != KeyCodes.KEY_SPACE
+ || !selectAllCheckBox.isEnabled()) {
return;
}
HeaderRow targetHeaderRow = getHeader()
@@ -3050,6 +3048,11 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
}
}
+ @Override
+ public void onSelectionAllowed(GridSelectionAllowedEvent event) {
+ updateEnable();
+ }
+
}
/**
@@ -5906,26 +5909,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
editor.setGrid(this);
- setSelectionModel(new SelectionModel<T>() {
-
- @Override
- public void select(T item) {
- }
-
- @Override
- public void deselect(T item) {
- }
-
- @Override
- public boolean isSelected(T item) {
- return false;
- }
-
- @Override
- public void deselectAll() {
- }
-
- });
+ setSelectionModel(new SelectionModel.NoSelectionModel<>());
escalator.getBody().setSpacerUpdater(gridSpacerUpdater);
@@ -7590,7 +7574,6 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
addColumnSkipSelectionColumnCheck(selectionColumn, 0);
- selectionColumn.setEnabled(isEnabled());
selectionColumn.initDone();
} else {
selectionColumn = null;
@@ -7662,7 +7645,9 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
* {@link SelectionModel.Single} or {@link SelectionModel.Multi}
*/
public void select(T row) {
- getSelectionModel().select(row);
+ if (getSelectionModel().isSelectionAllowed()) {
+ getSelectionModel().select(row);
+ }
}
/**
@@ -7679,7 +7664,9 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
* {@link SelectionModel.Single} or {@link SelectionModel.Multi}
*/
public void deselect(T row) {
- getSelectionModel().deselect(row);
+ if (getSelectionModel().isSelectionAllowed()) {
+ getSelectionModel().deselect(row);
+ }
}
/**
@@ -8101,6 +8088,20 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
return addHandler(handler, GridEnabledEvent.TYPE);
}
+ /**
+ * Register a selection allowed status change handler to this Grid. The
+ * event for this handler is fired when the Grid changes selection allowed
+ * state.
+ *
+ * @param handler
+ * the handler for the event
+ * @return the registration for the event
+ */
+ public HandlerRegistration addSelectionAllowedHandler(
+ GridSelectionAllowedHandler handler) {
+ return addHandler(handler, GridSelectionAllowedEvent.TYPE);
+ }
+
public HandlerRegistration addRowHeightChangedHandler(
RowHeightChangedHandler handler) {
return escalator.addHandler(handler, RowHeightChangedEvent.TYPE);
diff --git a/server/src/main/java/com/vaadin/ui/components/grid/MultiSelectionModelImpl.java b/server/src/main/java/com/vaadin/ui/components/grid/MultiSelectionModelImpl.java
index f85c781345..9c2b506107 100644
--- a/server/src/main/java/com/vaadin/ui/components/grid/MultiSelectionModelImpl.java
+++ b/server/src/main/java/com/vaadin/ui/components/grid/MultiSelectionModelImpl.java
@@ -324,16 +324,12 @@ public class MultiSelectionModelImpl<T> extends AbstractSelectionModel<T>
@Override
public void setReadOnly(boolean readOnly) {
- // TODO support read only in grid ?
- throw new UnsupportedOperationException(
- "Read only mode is not supported for grid.");
+ getState().selectionAllowed = readOnly;
}
@Override
public boolean isReadOnly() {
- // TODO support read only in grid ?
- throw new UnsupportedOperationException(
- "Read only mode is not supported for grid.");
+ return isUserSelectionAllowed();
}
@Override
@@ -429,6 +425,11 @@ public class MultiSelectionModelImpl<T> extends AbstractSelectionModel<T>
Objects.requireNonNull(addedItems);
Objects.requireNonNull(removedItems);
+ if (userOriginated && !isUserSelectionAllowed()) {
+ throw new IllegalStateException("Client tried to update selection"
+ + " although user selection is disallowed");
+ }
+
// if there are duplicates, some item is both added & removed, just
// discard that and leave things as was before
addedItems.removeIf(item -> removedItems.remove(item));
@@ -457,6 +458,10 @@ public class MultiSelectionModelImpl<T> extends AbstractSelectionModel<T>
}, userOriginated);
}
+ private boolean isUserSelectionAllowed() {
+ return getState(false).selectionAllowed;
+ }
+
private void doUpdateSelection(Consumer<Set<T>> handler,
boolean userOriginated) {
if (getParent() == null) {
diff --git a/server/src/main/java/com/vaadin/ui/components/grid/SingleSelectionModelImpl.java b/server/src/main/java/com/vaadin/ui/components/grid/SingleSelectionModelImpl.java
index ac1edaf576..6db6bfa61c 100644
--- a/server/src/main/java/com/vaadin/ui/components/grid/SingleSelectionModelImpl.java
+++ b/server/src/main/java/com/vaadin/ui/components/grid/SingleSelectionModelImpl.java
@@ -169,6 +169,10 @@ public class SingleSelectionModelImpl<T> extends AbstractSelectionModel<T>
* selection
*/
protected void setSelectedFromClient(String key) {
+ if (!isUserSelectionAllowed()) {
+ throw new IllegalStateException("Client tried to update selection"
+ + " although user selection is disallowed");
+ }
if (isKeySelected(key)) {
return;
}
@@ -224,6 +228,10 @@ public class SingleSelectionModelImpl<T> extends AbstractSelectionModel<T>
}
}
+ private boolean isUserSelectionAllowed() {
+ return getState(false).selectionAllowed;
+ }
+
/**
* Gets a wrapper for using this grid as a single select in a binder.
*
@@ -267,15 +275,12 @@ public class SingleSelectionModelImpl<T> extends AbstractSelectionModel<T>
@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.");
+ getState().selectionAllowed = readOnly;
}
@Override
public boolean isReadOnly() {
- throw new UnsupportedOperationException(
- "Read only is not supported for Grid.");
+ return isUserSelectionAllowed();
}
};
}
diff --git a/server/src/test/java/com/vaadin/tests/components/grid/GridMultiSelectionModelTest.java b/server/src/test/java/com/vaadin/tests/components/grid/GridMultiSelectionModelTest.java
index 3a57311bd7..aa601c67be 100644
--- a/server/src/test/java/com/vaadin/tests/components/grid/GridMultiSelectionModelTest.java
+++ b/server/src/test/java/com/vaadin/tests/components/grid/GridMultiSelectionModelTest.java
@@ -76,6 +76,21 @@ public class GridMultiSelectionModelTest {
}
}
+ private static class TestMultiSelectionModel
+ extends MultiSelectionModelImpl<Object> {
+
+ public TestMultiSelectionModel() {
+ getState(false).selectionAllowed = false;
+ }
+
+ @Override
+ protected void updateSelection(Set<Object> addedItems,
+ Set<Object> removedItems, boolean userOriginated) {
+ super.updateSelection(addedItems, removedItems, userOriginated);
+ }
+
+ }
+
@Before
public void setUp() {
grid = new Grid<>();
@@ -98,6 +113,13 @@ public class GridMultiSelectionModelTest {
}
@Test(expected = IllegalStateException.class)
+ public void throwExcpetionWhenSelectionIsDisallowed() {
+ TestMultiSelectionModel model = new TestMultiSelectionModel();
+ model.updateSelection(Collections.emptySet(), Collections.emptySet(),
+ true);
+ }
+
+ @Test(expected = IllegalStateException.class)
public void selectionModelChanged_usingPreviousSelectionModel_throws() {
grid.setSelectionMode(SelectionMode.SINGLE);
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
index 06ceb8bfc3..bae7c9c19b 100644
--- a/server/src/test/java/com/vaadin/tests/components/grid/GridSingleSelectionModelTest.java
+++ b/server/src/test/java/com/vaadin/tests/components/grid/GridSingleSelectionModelTest.java
@@ -48,6 +48,19 @@ public class GridSingleSelectionModelTest {
}
+ private static class TestSingleSelectionModel
+ extends SingleSelectionModelImpl<Object> {
+
+ public TestSingleSelectionModel() {
+ getState(false).selectionAllowed = false;
+ }
+
+ @Override
+ protected void setSelectedFromClient(String key) {
+ super.setSelectedFromClient(key);
+ }
+ }
+
private List<Person> selectionChanges;
private Grid<Person> grid;
private SingleSelectionModelImpl<Person> selectionModel;
@@ -65,6 +78,12 @@ public class GridSingleSelectionModelTest {
}
@Test(expected = IllegalStateException.class)
+ public void throwExceptionWhenSelectionIsDisallowed() {
+ TestSingleSelectionModel model = new TestSingleSelectionModel();
+ model.setSelectedFromClient("foo");
+ }
+
+ @Test(expected = IllegalStateException.class)
public void selectionModelChanged_usingPreviousSelectionModel_throws() {
grid.setSelectionMode(SelectionMode.MULTI);
diff --git a/shared/src/main/java/com/vaadin/shared/ui/grid/AbstractSelectionModelState.java b/shared/src/main/java/com/vaadin/shared/ui/grid/AbstractSelectionModelState.java
index 9cd29341b1..4e0e05c8bd 100644
--- a/shared/src/main/java/com/vaadin/shared/ui/grid/AbstractSelectionModelState.java
+++ b/shared/src/main/java/com/vaadin/shared/ui/grid/AbstractSelectionModelState.java
@@ -25,4 +25,9 @@ import com.vaadin.shared.communication.SharedState;
* @since 8.0
*/
public class AbstractSelectionModelState extends SharedState {
+
+ /**
+ * Whether the selection model allows selection from the client side.
+ */
+ public boolean selectionAllowed = true;
}
diff --git a/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java b/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java
index 70b7eab470..430692477d 100644
--- a/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java
+++ b/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java
@@ -36,8 +36,10 @@ import com.vaadin.ui.Label;
import com.vaadin.ui.MenuBar;
import com.vaadin.ui.MenuBar.Command;
import com.vaadin.ui.MenuBar.MenuItem;
+import com.vaadin.ui.MultiSelect;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Panel;
+import com.vaadin.ui.SingleSelect;
import com.vaadin.ui.StyleGenerator;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;
@@ -64,6 +66,8 @@ public class GridBasics extends AbstractTestUIWithLog {
public static final String CELL_STYLE_GENERATOR_EMPTY = "Empty string";
public static final String CELL_STYLE_GENERATOR_NULL = "Null";
+ private boolean isUserSelectionAllowed = true;
+
public static final String[] COLUMN_CAPTIONS = { "Column 0", "Column 1",
"Column 2", "Row Number", "Date", "HTML String", "Big Random",
"Small Random" };
@@ -403,6 +407,23 @@ public class GridBasics extends AbstractTestUIWithLog {
}
}).setCheckable(true);
+ MenuItem selectionAllowedItem = stateMenu
+ .addItem("Allow user selection", item -> {
+ isUserSelectionAllowed = !isUserSelectionAllowed;
+ if (grid.getSelectionModel() instanceof MultiSelectionModelImpl) {
+ MultiSelect<DataObject> multiSelect = grid
+ .asMultiSelect();
+ multiSelect.setReadOnly(isUserSelectionAllowed);
+ }
+ if (grid.getSelectionModel() instanceof SingleSelectionModelImpl) {
+ SingleSelect<DataObject> singleSelect = grid
+ .asSingleSelect();
+ singleSelect.setReadOnly(isUserSelectionAllowed);
+ }
+ });
+ selectionAllowedItem.setChecked(true);
+ selectionAllowedItem.setCheckable(true);
+
stateMenu.addItem("Column reorder listener",
toggleReorderListenerCommand).setCheckable(true);
@@ -492,6 +513,7 @@ public class GridBasics extends AbstractTestUIWithLog {
selectionListenerRegistration = ((SingleSelectionModelImpl<DataObject>) grid
.getSelectionModel())
.addSelectionListener(this::onSingleSelect);
+ grid.asSingleSelect().setReadOnly(isUserSelectionAllowed);
});
selectionModelItem.addItem("multi", menuItem -> {
switchToMultiSelect();
@@ -534,9 +556,12 @@ public class GridBasics extends AbstractTestUIWithLog {
private void switchToMultiSelect() {
if (!(grid.getSelectionModel() instanceof MultiSelectionModel)) {
selectionListenerRegistration.remove();
- ((MultiSelectionModelImpl<DataObject>) grid
- .setSelectionMode(SelectionMode.MULTI))
- .addSelectionListener(this::onMultiSelect);
+ MultiSelectionModelImpl<DataObject> model = (MultiSelectionModelImpl<DataObject>) grid
+ .setSelectionMode(SelectionMode.MULTI);
+ model.addSelectionListener(this::onMultiSelect);
+ grid.asMultiSelect().setReadOnly(isUserSelectionAllowed);
+ selectionListenerRegistration = model
+ .addSelectionListener(this::onMultiSelect);
}
}
diff --git a/uitest/src/test/java/com/vaadin/tests/components/grid/GridSelectionTest.java b/uitest/src/test/java/com/vaadin/tests/components/grid/GridSelectionTest.java
index e42fcf2d69..6682d0bec5 100644
--- a/uitest/src/test/java/com/vaadin/tests/components/grid/GridSelectionTest.java
+++ b/uitest/src/test/java/com/vaadin/tests/components/grid/GridSelectionTest.java
@@ -255,6 +255,163 @@ public class GridSelectionTest extends GridBasicsTest {
"Exception occured, java.lang.NullPointerException: null"));
}
+ @Test
+ public void singleSelectUserSelectionDisallowedSpaceSelectionNoOp() {
+ openTestURL();
+ setSelectionModelSingle();
+ getGridElement().focus();
+ getGridElement().sendKeys(Keys.DOWN, Keys.SPACE);
+ assertTrue("row was selected when selection was allowed",
+ getRow(1).isSelected());
+ toggleUserSelectionAllowed();
+ getGridElement().sendKeys(Keys.SPACE);
+ assertTrue("deselect disallowed", getRow(1).isSelected());
+ getGridElement().sendKeys(Keys.DOWN, Keys.SPACE);
+ assertFalse("select disallowed", getRow(2).isSelected());
+ assertTrue("old selection remains", getRow(1).isSelected());
+ toggleUserSelectionAllowed();
+ getGridElement().sendKeys(Keys.SPACE);
+ assertTrue("select allowed again", getRow(2).isSelected());
+ assertFalse("old selection removed", getRow(1).isSelected());
+
+ }
+
+ @Test
+ public void singleSelectUserSelectionDisallowedClickSelectionNoOp() {
+ openTestURL();
+ setSelectionModelSingle();
+ getGridElement().getCell(1, 0).click();
+ assertTrue("selection allowed, should have been selected",
+ getRow(1).isSelected());
+ toggleUserSelectionAllowed();
+ getGridElement().getCell(1, 0).click();
+ assertTrue("deselect disallowed, should remain selected",
+ getRow(1).isSelected());
+ getGridElement().getCell(2, 0).click();
+ assertFalse("select disallowed, should not have been selected",
+ getRow(2).isSelected());
+ assertTrue("select disallowed, old selection should have remained",
+ getRow(1).isSelected());
+ toggleUserSelectionAllowed();
+ getGridElement().getCell(2, 0).click();
+ assertTrue("select allowed again, row should have been selected",
+ getRow(2).isSelected());
+ assertFalse("old selection removed", getRow(1).isSelected());
+
+ }
+
+ @Test
+ public void multiSelectUserSelectionDisallowedSpaceSelectionNoOp() {
+ openTestURL();
+ setSelectionModelMulti();
+ getGridElement().focus();
+ getGridElement().sendKeys(Keys.DOWN, Keys.SPACE);
+ assertTrue("selection allowed, should have been selected",
+ getRow(1).isSelected());
+ toggleUserSelectionAllowed();
+ getGridElement().sendKeys(Keys.SPACE);
+ assertTrue("deselect disallowed, should remain selected",
+ getRow(1).isSelected());
+ getGridElement().sendKeys(Keys.DOWN, Keys.SPACE);
+ assertFalse("select disallowed, should not have been selected",
+ getRow(2).isSelected());
+ assertTrue("select disallowed, old selection should have remained",
+ getRow(1).isSelected());
+
+ toggleUserSelectionAllowed();
+ getGridElement().sendKeys(Keys.SPACE);
+ assertTrue("select allowed again, row should have been selected",
+ getRow(2).isSelected());
+ assertTrue(
+ "select allowed again but old selection should have remained",
+ getRow(1).isSelected());
+ }
+
+ @Test
+ public void multiSelectUserSelectionDisallowedCheckboxSelectionNoOp() {
+ openTestURL();
+ setSelectionModelMulti();
+ assertTrue(getSelectionCheckbox(0).isEnabled());
+ toggleUserSelectionAllowed();
+ assertFalse(getSelectionCheckbox(0).isEnabled());
+
+ // Select by clicking on checkbox (should always fail as it is disabled)
+ getSelectionCheckbox(0).click();
+ assertFalse(getGridElement().getRow(0).isSelected());
+ // Select by clicking on cell (should fail)
+ getGridElement().getCell(0, 0).click();
+ assertFalse(getGridElement().getRow(0).isSelected());
+
+ toggleUserSelectionAllowed();
+ assertTrue(getSelectionCheckbox(0).isEnabled());
+ getSelectionCheckbox(0).click();
+ assertTrue(getGridElement().getRow(0).isSelected());
+ }
+
+ @Test
+ public void multiSelectUserSelectionDisallowedCheckboxSelectAllNoOp() {
+ openTestURL();
+ setSelectionModelMulti();
+
+ assertTrue(getSelectAllCheckbox().isEnabled());
+ toggleUserSelectionAllowed();
+ assertFalse(getSelectAllCheckbox().isEnabled());
+
+ // Select all by clicking on checkbox (should not select)
+ getSelectAllCheckbox().click();
+ assertFalse(getSelectAllCheckbox().isSelected());
+ assertFalse(getGridElement().getRow(0).isSelected());
+ assertFalse(getGridElement().getRow(10).isSelected());
+
+ // Select all by clicking on header cell (should not select)
+ getGridElement().getHeaderCell(0, 0).click();
+ assertFalse(getSelectAllCheckbox().isSelected());
+ assertFalse(getGridElement().getRow(0).isSelected());
+ assertFalse(getGridElement().getRow(10).isSelected());
+
+ // Select all by press SPACE on the header cell (should not select)
+ getGridElement().getHeaderCell(0, 0).sendKeys(Keys.SPACE);
+ assertFalse(getSelectAllCheckbox().isSelected());
+ assertFalse(getGridElement().getRow(0).isSelected());
+ assertFalse(getGridElement().getRow(10).isSelected());
+
+ toggleUserSelectionAllowed();
+
+ assertTrue(getSelectAllCheckbox().isEnabled());
+ getSelectAllCheckbox().click();
+ assertTrue(getGridElement().getRow(0).isSelected());
+ assertTrue(getGridElement().getRow(10).isSelected());
+ }
+
+ @Test
+ public void singleSelectUserSelectionDisallowedServerSelect() {
+ openTestURL();
+ setSelectionModelSingle();
+ toggleUserSelectionAllowed();
+
+ toggleFirstRowSelection();
+ assertTrue(getGridElement().getRow(0).isSelected());
+ }
+
+ @Test
+ public void multiSelectUserSelectionDisallowedServerSelect() {
+ openTestURL();
+ setSelectionModelMulti();
+ toggleUserSelectionAllowed();
+
+ toggleFirstRowSelection();
+ assertTrue(getGridElement().getRow(0).isSelected());
+ }
+
+ private void toggleUserSelectionAllowed() {
+ selectMenuPath("Component", "State", "Allow user selection");
+ }
+
+ private WebElement getSelectionCheckbox(int row) {
+ return getGridElement().getCell(row, 0)
+ .findElement(By.tagName("input"));
+ }
+
private void waitUntilCheckBoxValue(final WebElement checkBoxElememnt,
final boolean expectedValue) {
waitUntil(new ExpectedCondition<Boolean>() {