import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.logging.Logger;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.CheckBox;
import com.vaadin.client.widget.grid.DataAvailableHandler;
import com.vaadin.client.widget.grid.events.SelectAllEvent;
import com.vaadin.client.widget.grid.events.SelectAllHandler;
+import com.vaadin.client.widget.grid.selection.HasUserSelectionAllowed;
import com.vaadin.client.widget.grid.selection.MultiSelectionRenderer;
import com.vaadin.client.widget.grid.selection.SelectionModel;
import com.vaadin.client.widget.grid.selection.SelectionModel.Multi;
import com.vaadin.client.widget.grid.selection.SpaceSelectHandler;
import com.vaadin.client.widgets.Grid;
+import com.vaadin.client.widgets.Grid.Column;
import com.vaadin.client.widgets.Grid.HeaderCell;
+import com.vaadin.client.widgets.Grid.SelectionColumn;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.grid.GridState;
import com.vaadin.shared.ui.grid.Range;
}
}
+ @OnStateChange("userSelectionAllowed")
+ void updateUserSelectionAllowed() {
+ if (selectionModel instanceof HasUserSelectionAllowed) {
+ ((HasUserSelectionAllowed) selectionModel)
+ .setUserSelectionAllowed(getState().userSelectionAllowed);
+ } else {
+ getLogger().warning("userSelectionAllowed set to "
+ + getState().userSelectionAllowed
+ + " but the selection model does not implement "
+ + HasUserSelectionAllowed.class.getSimpleName());
+ }
+ }
+
+ private static Logger getLogger() {
+ return Logger.getLogger(MultiSelectionModelConnector.class.getName());
+ }
+
+ /**
+ * The default multi selection model used for this connector.
+ *
+ */
protected class MultiSelectionModel extends AbstractSelectionModel
- implements SelectionModel.Multi.Batched<JsonObject> {
+ implements SelectionModel.Multi.Batched<JsonObject>,
+ HasUserSelectionAllowed<JsonObject> {
private ComplexRenderer<Boolean> renderer = null;
private Set<RowHandle<JsonObject>> selected = new HashSet<RowHandle<JsonObject>>();
private HandlerRegistration dataAvailable;
private Range availableRows;
private boolean batchSelect = false;
+ private boolean userSelectionAllowed = true;
@Override
public void setGrid(Grid<JsonObject> grid) {
public Collection<JsonObject> getDeselectedRowsBatch() {
return Collections.unmodifiableSet(getRows(deselected));
}
+
+ @Override
+ public boolean isUserSelectionAllowed() {
+ return userSelectionAllowed;
+ }
+
+ @Override
+ public void setUserSelectionAllowed(boolean userSelectionAllowed) {
+ this.userSelectionAllowed = userSelectionAllowed;
+ for (Column<?, ?> c : getGrid().getColumns()) {
+ if (c instanceof SelectionColumn) {
+ ((SelectionColumn) c)
+ .setUserSelectionAllowed(userSelectionAllowed);
+ }
+ }
+ }
}
}
*/
package com.vaadin.client.connectors;
+import java.util.logging.Logger;
+
import com.vaadin.client.ServerConnector;
import com.vaadin.client.annotations.OnStateChange;
import com.vaadin.client.data.DataSource.RowHandle;
import com.vaadin.client.renderers.Renderer;
import com.vaadin.client.widget.grid.selection.ClickSelectHandler;
+import com.vaadin.client.widget.grid.selection.HasUserSelectionAllowed;
import com.vaadin.client.widget.grid.selection.SelectionModel;
import com.vaadin.client.widget.grid.selection.SelectionModel.Single;
import com.vaadin.client.widget.grid.selection.SpaceSelectHandler;
selectionModel.setDeselectAllowed(getState().deselectAllowed);
}
+ @OnStateChange("userSelectionAllowed")
+ void updateUserSelectionAllowed() {
+
+ if (selectionModel instanceof HasUserSelectionAllowed) {
+ ((HasUserSelectionAllowed) selectionModel)
+ .setUserSelectionAllowed(getState().userSelectionAllowed);
+ } else {
+ getLogger().warning("userSelectionAllowed set to "
+ + getState().userSelectionAllowed
+ + " but the selection model does not implement "
+ + HasUserSelectionAllowed.class.getSimpleName());
+ }
+ }
+
+ private static Logger getLogger() {
+ return Logger.getLogger(SingleSelectionModelConnector.class.getName());
+ }
+
/**
* SingleSelectionModel without a selection column renderer.
*/
public class SingleSelectionModel extends AbstractSelectionModel
- implements SelectionModel.Single<JsonObject> {
+ implements SelectionModel.Single<JsonObject>,
+ HasUserSelectionAllowed<JsonObject> {
private RowHandle<JsonObject> selectedRow;
private boolean deselectAllowed;
+ private boolean userSelectionAllowed = true;
@Override
public Renderer<Boolean> getSelectionColumnRenderer() {
public boolean isDeselectAllowed() {
return deselectAllowed;
}
+
+ @Override
+ public boolean isUserSelectionAllowed() {
+ return userSelectionAllowed;
+ }
+
+ @Override
+ public void setUserSelectionAllowed(boolean userSelectionAllowed) {
+ this.userSelectionAllowed = userSelectionAllowed;
+ }
+
}
}
\ No newline at end of file
@Override
public void onClick(GridClickEvent event) {
+ if (!grid.isUserSelectionAllowed()) {
+ return;
+ }
+
T row = (T) event.getTargetCell().getRow();
if (!grid.isSelected(row)) {
grid.select(row);
--- /dev/null
+/*
+ * 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.widget.grid.selection;
+
+/**
+ * Interface implemented by selection models which support disabling client side
+ * selection while still allowing programmatic selection on the server.
+ *
+ * @param <T>
+ * Grid's row type
+ */
+public interface HasUserSelectionAllowed<T> extends SelectionModel<T> {
+
+ /**
+ * Checks if the user is allowed to change the selection.
+ *
+ * @return <code>true</code> if the user is allowed to change the selection,
+ * <code>false</code> otherwise
+ */
+ public boolean isUserSelectionAllowed();
+
+ /**
+ * Sets whether the user is allowed to change the selection.
+ *
+ * @param userSelectionAllowed
+ * <code>true</code> if the user is allowed to change the
+ * selection, <code>false</code> otherwise
+ */
+ public void setUserSelectionAllowed(boolean userSelectionAllowed);
+
+}
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.isUserSelectionAllowed());
}
@Override
}
protected void setSelected(final int logicalRow, final boolean select) {
+ if (!grid.isUserSelectionAllowed()) {
+ return;
+ }
T row = grid.getDataSource().getRow(logicalRow);
if (select) {
grid.select(row);
* @since 7.4
*/
public class SelectionModelMulti<T> extends AbstractRowHandleSelectionModel<T>
- implements SelectionModel.Multi.Batched<T> {
+ implements SelectionModel.Multi.Batched<T>, HasUserSelectionAllowed<T> {
private final LinkedHashSet<RowHandle<T>> selectedRows;
private Renderer<Boolean> renderer;
/* Event handling for selection with space key */
private SpaceSelectHandler<T> spaceSelectHandler;
+ private boolean userSelectionAllowed = true;
public SelectionModelMulti() {
grid = null;
}
return rows;
}
+
+ @Override
+ public boolean isUserSelectionAllowed() {
+ return userSelectionAllowed;
+ }
+
+ @Override
+ public void setUserSelectionAllowed(boolean userSelectionAllowed) {
+ this.userSelectionAllowed = userSelectionAllowed;
+ }
}
* @since 7.4
*/
public class SelectionModelSingle<T> extends AbstractRowHandleSelectionModel<T>
- implements SelectionModel.Single<T> {
+ implements SelectionModel.Single<T>, HasUserSelectionAllowed<T> {
private Grid<T> grid;
private RowHandle<T> selectedRow;
private ClickSelectHandler<T> clickSelectHandler;
private boolean deselectAllowed = true;
+ private boolean userSelectionAllowed = true;
@Override
public boolean isSelected(T row) {
}
}
+ @Override
+ public boolean isUserSelectionAllowed() {
+ return userSelectionAllowed;
+ }
+
+ @Override
+ public void setUserSelectionAllowed(boolean userSelectionAllowed) {
+ this.userSelectionAllowed = userSelectionAllowed;
+ }
+
}
@Override
public void onKeyDown(GridKeyDownEvent event) {
+ if (!grid.isUserSelectionAllowed()) {
+ return;
+ }
+
if (event.getNativeKeyCode() != KeyCodes.KEY_SPACE || spaceDown) {
return;
}
import com.vaadin.client.widget.grid.events.SelectAllEvent;
import com.vaadin.client.widget.grid.events.SelectAllHandler;
import com.vaadin.client.widget.grid.selection.HasSelectionHandlers;
+import com.vaadin.client.widget.grid.selection.HasUserSelectionAllowed;
import com.vaadin.client.widget.grid.selection.MultiSelectionRenderer;
import com.vaadin.client.widget.grid.selection.SelectionEvent;
import com.vaadin.client.widget.grid.selection.SelectionHandler;
checkBox.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
+ if (!grid.isUserSelectionAllowed()) {
+ return;
+ }
T row = pinnedRowHandle.getRow();
if (grid.isSelected(row)) {
grid.deselect(row);
private boolean initDone = false;
private boolean selected = false;
private CheckBox selectAllCheckBox;
+ private boolean userSelectionAllowed = true;
+ private boolean enabled = true;
SelectionColumn(final Renderer<Boolean> selectColumnRenderer) {
super(selectColumnRenderer);
if (selectAllCheckBox == null) {
selectAllCheckBox = GWT.create(CheckBox.class);
+ selectAllCheckBox.setEnabled(enabled && userSelectionAllowed);
selectAllCheckBox.setStylePrimaryName(
getStylePrimaryName() + SELECT_ALL_CHECKBOX_CLASSNAME);
selectAllCheckBox.addValueChangeHandler(
@Override
public void onValueChange(
ValueChangeEvent<Boolean> event) {
+ if (!isUserSelectionAllowed()) {
+ return;
+ }
if (event.getValue()) {
fireEvent(new SelectAllEvent<T>(model));
selected = true;
addHeaderClickHandler(new HeaderClickHandler() {
@Override
public void onClick(GridClickEvent event) {
+ if (!userSelectionAllowed) {
+ return;
+ }
+
CellReference<?> targetCell = event.getTargetCell();
int defaultRowIndex = getHeader().getRows()
.indexOf(getDefaultHeaderRow());
if (event.getNativeKeyCode() != KeyCodes.KEY_SPACE) {
return;
}
+ if (!isUserSelectionAllowed()) {
+ return;
+ }
+
HeaderRow targetHeaderRow = getHeader()
.getRow(event.getFocusedCell().getRowIndex());
if (!targetHeaderRow.isDefault()) {
* to disable it.
*/
public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
if (selectAllCheckBox != null) {
- selectAllCheckBox.setEnabled(enabled);
+ selectAllCheckBox.setEnabled(enabled && userSelectionAllowed);
}
}
public void onEnabled(boolean enabled) {
setEnabled(enabled);
}
+
+ /**
+ * Sets whether the user is allowed to change the selection.
+ *
+ * @param userSelectionAllowed
+ * <code>true</code> if the user is allowed to change the
+ * selection, <code>false</code> otherwise
+ */
+ public void setUserSelectionAllowed(boolean userSelectionAllowed) {
+ if (userSelectionAllowed == this.userSelectionAllowed) {
+ return;
+ }
+
+ this.userSelectionAllowed = userSelectionAllowed;
+ // Update checkbox state
+ setEnabled(enabled);
+ // Re-render select checkboxes
+ getEscalator().getBody().refreshRows(0,
+ getEscalator().getBody().getRowCount());
+ }
}
/**
}
return null;
}
+
+ /**
+ * Checks if selection by the user is allowed in the grid.
+ *
+ * @return <code>true</code> if selection by the user is allowed by the
+ * selection model (the default), <code>false</code> otherwise
+ */
+ public boolean isUserSelectionAllowed() {
+ if (!(getSelectionModel() instanceof HasUserSelectionAllowed)) {
+ // Selection model does not support toggling user selection allowed
+ // - old default is to always allow selection
+ return true;
+ }
+ return ((HasUserSelectionAllowed) getSelectionModel())
+ .isUserSelectionAllowed();
+ }
}
});
----
+[[components.grid.selection.disallowuser]]
+=== Disallowing User Selection
+It is possible to prevent the user from changing the selection in grid for both single- and multi-selection models:
+
+[source, java]
+----
+HasUserSelectionAllowed model = (HasUserSelectionAllowed) grid.getSelectionModel();
+model.setUserSelectionAllowed(false);
+----
+
+[NOTE]
+Both `SingleSelectionModel` and `MultiSelectModel` implement `HasUserSelectionAllowed` so the cast is generally safe.
+
[[components.grid.selection.clicks]]
=== Focus and Clicks
import com.vaadin.shared.ui.grid.selection.SingleSelectionModelServerRpc;
import com.vaadin.shared.ui.grid.selection.SingleSelectionModelState;
import com.vaadin.shared.util.SharedUtil;
+import com.vaadin.ui.Grid.SelectionModel.HasUserSelectionAllowed;
import com.vaadin.ui.declarative.DesignAttributeHandler;
import com.vaadin.ui.declarative.DesignContext;
import com.vaadin.ui.declarative.DesignException;
}
}
- private void bindFields(List<Field<?>> fields,
- Item itemDataSource) {
+ private void bindFields(List<Field<?>> fields, Item itemDataSource) {
for (Field<?> field : fields) {
- if (itemDataSource.getItemProperty(getPropertyId(field))
- != null) {
+ if (itemDataSource
+ .getItemProperty(getPropertyId(field)) != null) {
bind(field, getPropertyId(field));
}
}
* SelectionModel should extend {@link AbstractGridExtension}.
*/
public interface SelectionModel extends Serializable, Extension {
+
+ /**
+ * Interface implemented by selection models which support disabling
+ * client side selection while still allowing programmatic selection on
+ * the server.
+ *
+ */
+ public interface HasUserSelectionAllowed extends SelectionModel {
+
+ /**
+ * Checks if the user is allowed to change the selection.
+ *
+ * @return <code>true</code> if the user is allowed to change the
+ * selection, <code>false</code> otherwise
+ */
+ public boolean isUserSelectionAllowed();
+
+ /**
+ * Sets whether the user is allowed to change the selection.
+ *
+ * @param userSelectionAllowed
+ * <code>true</code> if the user is allowed to change the
+ * selection, <code>false</code> otherwise
+ */
+ public void setUserSelectionAllowed(boolean userSelectionAllowed);
+
+ }
+
/**
* Checks whether an item is selected or not.
*
* A default implementation of a {@link SelectionModel.Single}
*/
public static class SingleSelectionModel extends AbstractSelectionModel
- implements SelectionModel.Single {
+ implements SelectionModel.Single, HasUserSelectionAllowed {
@Override
protected void extend(AbstractClientConnector target) {
@Override
public void select(String rowKey) {
+ if (!isUserSelectionAllowed()) {
+ throw new IllegalStateException(
+ "Client tried to select '" + rowKey
+ + "' although user selection is disallowed");
+ }
SingleSelectionModel.this.select(getItemId(rowKey), false);
}
});
protected SingleSelectionModelState getState() {
return (SingleSelectionModelState) super.getState();
}
+
+ @Override
+ protected SingleSelectionModelState getState(boolean markAsDirty) {
+ return (SingleSelectionModelState) super.getState(markAsDirty);
+ }
+
+ @Override
+ public boolean isUserSelectionAllowed() {
+ return getState(false).userSelectionAllowed;
+ }
+
+ @Override
+ public void setUserSelectionAllowed(boolean userSelectionAllowed) {
+ getState().userSelectionAllowed = userSelectionAllowed;
+ }
}
/**
public void reset() {
// NOOP
}
+
}
/**
* A default implementation of a {@link SelectionModel.Multi}
*/
public static class MultiSelectionModel extends AbstractSelectionModel
- implements SelectionModel.Multi {
+ implements SelectionModel.Multi,
+ SelectionModel.HasUserSelectionAllowed {
/**
* The default selection size limit.
@Override
public void select(List<String> rowKeys) {
+ if (!isUserSelectionAllowed()) {
+ throw new IllegalStateException(
+ "Client tried to select '" + rowKeys
+ + "' although user selection is disallowed");
+ }
+
List<Object> items = new ArrayList<Object>();
for (String rowKey : rowKeys) {
items.add(getItemId(rowKey));
@Override
public void deselect(List<String> rowKeys) {
+ if (!isUserSelectionAllowed()) {
+ throw new IllegalStateException(
+ "Client tried to deselect '" + rowKeys
+ + "' although user selection is disallowed");
+ }
+
List<Object> items = new ArrayList<Object>();
for (String rowKey : rowKeys) {
items.add(getItemId(rowKey));
@Override
public void selectAll() {
+ if (!isUserSelectionAllowed()) {
+ throw new IllegalStateException(
+ "Client tried to select all although user selection is disallowed");
+ }
+
MultiSelectionModel.this.selectAll(false);
}
@Override
public void deselectAll() {
+ if (!isUserSelectionAllowed()) {
+ throw new IllegalStateException(
+ "Client tried to deselect all although user selection is disallowed");
+ }
+
MultiSelectionModel.this.deselectAll(false);
}
});
protected MultiSelectionModelState getState() {
return (MultiSelectionModelState) super.getState();
}
+
+ @Override
+ protected MultiSelectionModelState getState(boolean markAsDirty) {
+ return (MultiSelectionModelState) super.getState(markAsDirty);
+ }
+
+ @Override
+ public boolean isUserSelectionAllowed() {
+ return getState(false).userSelectionAllowed;
+ }
+
+ @Override
+ public void setUserSelectionAllowed(boolean userSelectionAllowed) {
+ getState().userSelectionAllowed = userSelectionAllowed;
+ }
}
/**
Item item = cell.getItem();
Property itemProperty = item.getItemProperty(cell.getPropertyId());
- Object modelValue =
- itemProperty == null ? null : itemProperty.getValue();
+ Object modelValue = itemProperty == null ? null
+ : itemProperty.getValue();
data.put(columnKeys.key(cell.getPropertyId()), AbstractRenderer
.encodeValue(modelValue, renderer, converter, getLocale()));
private FieldGroup editorFieldGroup = new CustomFieldGroup();
/**
- * Poperty ID to Field mapping that stores editor fields set by {@link
- * #setEditorField(Object, Field)}.
+ * Poperty ID to Field mapping that stores editor fields set by
+ * {@link #setEditorField(Object, Field)}.
*/
private Map<Object, Field<?>> editorFields = new HashMap<Object, Field<?>>();
}
/**
- * Sets the column resize mode to use. The default mode is {@link ColumnResizeMode#ANIMATED}.
+ * Sets the column resize mode to use. The default mode is
+ * {@link ColumnResizeMode#ANIMATED}.
*
- * @param mode a ColumnResizeMode value
-
+ * @param mode
+ * a ColumnResizeMode value
+ *
* @since 7.7.5
*/
public void setColumnResizeMode(ColumnResizeMode mode) {
}
/**
- * Returns the current column resize mode. The default mode is {@link ColumnResizeMode#ANIMATED}.
+ * Returns the current column resize mode. The default mode is
+ * {@link ColumnResizeMode#ANIMATED}.
*
* @return a ColumnResizeMode value
*
Field<?> editor = editorFieldGroup.getField(propertyId);
- // If field group has no field for this property, see if we have it stored
+ // If field group has no field for this property, see if we have it
+ // stored
if (editor == null) {
editor = editorFields.get(propertyId);
if (editor != null) {
editorFieldGroup.setItemDataSource(item);
for (Column column : getColumns()) {
- column.getState().editorConnector =
- item.getItemProperty(column.getPropertyId()) == null
- ? null : getEditorField(column.getPropertyId());
+ column.getState().editorConnector = item
+ .getItemProperty(column.getPropertyId()) == null ? null
+ : getEditorField(column.getPropertyId());
}
editorActive = true;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import org.junit.After;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.event.SelectionEvent;
import com.vaadin.event.SelectionEvent.SelectionListener;
+import com.vaadin.shared.ui.grid.selection.MultiSelectionModelServerRpc;
import com.vaadin.shared.ui.grid.selection.MultiSelectionModelState;
+import com.vaadin.ui.ComponentTest;
import com.vaadin.ui.Grid;
+import com.vaadin.ui.Grid.SelectionModel.HasUserSelectionAllowed;
public class MultiSelectionModelTest {
}
Assert.fail("Not all items were correctly selected");
}
+
+ @Test(expected = IllegalStateException.class)
+ public void refuseSelectWhenUserSelectionDisallowed() {
+ ((HasUserSelectionAllowed) grid.getSelectionModel())
+ .setUserSelectionAllowed(false);
+ MultiSelectionModelServerRpc serverRpc = ComponentTest.getRpcProxy(
+ grid.getSelectionModel(), MultiSelectionModelServerRpc.class);
+ serverRpc.select(Collections.singletonList("a"));
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void refuseDeselectWhenUserSelectionDisallowed() {
+ ((HasUserSelectionAllowed) grid.getSelectionModel())
+ .setUserSelectionAllowed(false);
+ MultiSelectionModelServerRpc serverRpc = ComponentTest.getRpcProxy(
+ grid.getSelectionModel(), MultiSelectionModelServerRpc.class);
+ serverRpc.deselect(Collections.singletonList("a"));
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void refuseSelectAllWhenUserSelectionDisallowed() {
+ ((HasUserSelectionAllowed) grid.getSelectionModel())
+ .setUserSelectionAllowed(false);
+ MultiSelectionModelServerRpc serverRpc = ComponentTest.getRpcProxy(
+ grid.getSelectionModel(), MultiSelectionModelServerRpc.class);
+ serverRpc.selectAll();
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void refuseDeselectAllWhenUserSelectionDisallowed() {
+ ((HasUserSelectionAllowed) grid.getSelectionModel())
+ .setUserSelectionAllowed(false);
+ MultiSelectionModelServerRpc serverRpc = ComponentTest.getRpcProxy(
+ grid.getSelectionModel(), MultiSelectionModelServerRpc.class);
+ serverRpc.deselectAll();
+ }
+
}
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.event.SelectionEvent;
import com.vaadin.event.SelectionEvent.SelectionListener;
+import com.vaadin.shared.ui.grid.selection.SingleSelectionModelServerRpc;
+import com.vaadin.ui.ComponentTest;
import com.vaadin.ui.Grid;
import com.vaadin.ui.Grid.SelectionMode;
+import com.vaadin.ui.Grid.SelectionModel.HasUserSelectionAllowed;
import com.vaadin.ui.Grid.SingleSelectionModel;
public class SingleSelectionModelTest {
}
});
}
+
+ @Test(expected = IllegalStateException.class)
+ public void refuseSelectionWhenUserSelectionDisallowed() {
+ ((HasUserSelectionAllowed) grid.getSelectionModel())
+ .setUserSelectionAllowed(false);
+ SingleSelectionModelServerRpc serverRpc = ComponentTest.getRpcProxy(
+ grid.getSelectionModel(), SingleSelectionModelServerRpc.class);
+ serverRpc.select("a");
+ }
+
}
--- /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;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashSet;
+
+import org.junit.Assert;
+
+import com.vaadin.server.ClientConnector;
+import com.vaadin.server.ServerRpcManager;
+import com.vaadin.shared.communication.ServerRpc;
+
+import elemental.json.JsonObject;
+
+/**
+ * Base class for component unit tests, providing helper methods for e.g.
+ * invoking RPC and updating diff state.
+ */
+public class ComponentTest {
+
+ /**
+ * Perform operations on the component similar to what would be done when
+ * the component state is communicated to the client, e.g. update diff state
+ * and mark as clean.
+ *
+ * @param component
+ * the component to update
+ */
+ public static void syncToClient(AbstractComponent component) {
+ updateDiffState(component);
+ component.getUI().getConnectorTracker().markClean(component);
+ }
+
+ /**
+ * Checks if the connector has been marked dirty.
+ *
+ * @param connector
+ * the connector to check
+ * @return <code>true</code> if the connector has been marked dirty,
+ * <code>false</code> otherwise
+ */
+ public static boolean isDirty(ClientConnector connector) {
+ return connector.getUI().getConnectorTracker().isDirty(connector);
+ }
+
+ /**
+ * Updates the stored diff state from the current component state.
+ *
+ * @param rta
+ * the component to update
+ */
+ public static void updateDiffState(AbstractComponent component) {
+ component.getUI().getSession().getCommunicationManager()
+ .encodeState(component, component.getState());
+
+ }
+
+ /**
+ * Gets the server rpc handler registered for a component.
+ *
+ * @param connector
+ * the connector which listens to the RPC
+ * @param serverRpcClass
+ * the server RPC class
+ * @return the server RPC handler
+ */
+ public static <T extends ServerRpc> T getRpcProxy(ClientConnector connector,
+ Class<T> serverRpcClass) {
+ try {
+ ServerRpcManager<?> rpcManager = connector
+ .getRpcManager(serverRpcClass.getName());
+ Method method = ServerRpcManager.class
+ .getDeclaredMethod("getImplementation");
+ method.setAccessible(true);
+ return serverRpcClass.cast(method.invoke(rpcManager));
+ } catch (ReflectiveOperationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Asserts the set of properties that would be sent as state changes for the
+ * given connector.
+ *
+ * @param connector
+ * the connector that has state changes
+ * @param message
+ * the message to show if the properties are not as expected
+ * @param expectedProperties
+ * names of the expected properties
+ */
+ public static void assertEncodedStateProperties(ClientConnector connector,
+ String message, String... expectedProperties) {
+ assert connector.isAttached();
+
+ JsonObject encodeState = connector.encodeState();
+
+ // Collect to HashSet so that order doesn't matter
+ Assert.assertEquals(message,
+ new HashSet<String>(Arrays.asList(expectedProperties)),
+ new HashSet<String>(Arrays.asList(encodeState.keys())));
+ }
+
+}
\ No newline at end of file
/* Select All -checkbox status */
public boolean allSelected;
+ public boolean userSelectionAllowed = true;
}
/* Allow deselecting rows */
public boolean deselectAllowed = true;
+ public boolean userSelectionAllowed = true;
}
import com.vaadin.ui.Grid.RowStyleGenerator;
import com.vaadin.ui.Grid.SelectionMode;
import com.vaadin.ui.Grid.SelectionModel;
+import com.vaadin.ui.Grid.SelectionModel.HasUserSelectionAllowed;
import com.vaadin.ui.Label;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Panel;
private int containerDelay = 0;
private boolean singleSelectAllowDeselect = true;
+ private boolean allowUserSelection = true;
private IndexedContainer ds;
private Grid grid;
} else {
grid.removeSelectionListener(selectionListener);
}
+
+ ((HasUserSelectionAllowed) grid.getSelectionModel())
+ .setUserSelectionAllowed(allowUserSelection);
}
});
}
}
});
+ createBooleanAction("Allow user selection", "State", allowUserSelection,
+ new Command<Grid, Boolean>() {
+ @Override
+ public void execute(Grid c, Boolean value, Object data) {
+ allowUserSelection = value.booleanValue();
+
+ SelectionModel model = c.getSelectionModel();
+ ((HasUserSelectionAllowed) model)
+ .setUserSelectionAllowed(allowUserSelection);
+ }
+ });
createBooleanAction("Column Reordering Allowed", "State", false,
new Command<Grid, Boolean>() {
}
}, null);
- createBooleanAction("Simple resize mode", "Columns", false, new Command<Grid, Boolean>() {
- @Override
- public void execute(Grid g, Boolean value, Object data) {
- g.setColumnResizeMode(value ? ColumnResizeMode.SIMPLE : ColumnResizeMode.ANIMATED);
- }
- });
+ createBooleanAction("Simple resize mode", "Columns", false,
+ new Command<Grid, Boolean>() {
+ @Override
+ public void execute(Grid g, Boolean value, Object data) {
+ g.setColumnResizeMode(value ? ColumnResizeMode.SIMPLE
+ : ColumnResizeMode.ANIMATED);
+ }
+ });
}
private static String getColumnProperty(int c) {
selectMenuPath("Component", "Body rows", "Select first row");
}
+ private void toggleUserSelectionAllowed() {
+ selectMenuPath("Component", "State", "Allow user selection");
+ }
+
private GridRowElement getRow(int i) {
return getGridElement().getRow(i);
}
getGridElement().getCell(0, 0).click();
assertTrue("row should become selected", getRow(0).isSelected());
}
+
+ @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());
+
+ 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 WebElement getSelectAllCheckbox() {
+ return getGridElement().getHeaderCell(0, 0)
+ .findElement(By.tagName("input"));
+ }
+
+ private WebElement getSelectionCheckbox(int row) {
+ return getGridElement().getCell(row, 0)
+ .findElement(By.tagName("input"));
+ }
+
}