aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java1
-rw-r--r--client/src/main/java/com/vaadin/client/connectors/grid/MultiSelectionModelConnector.java180
-rw-r--r--client/src/main/java/com/vaadin/client/connectors/grid/SingleSelectionModelConnector.java12
-rw-r--r--client/src/main/java/com/vaadin/client/widget/grid/events/SelectAllEvent.java55
-rw-r--r--client/src/main/java/com/vaadin/client/widgets/Grid.java190
-rw-r--r--server/src/main/java/com/vaadin/data/SelectionModel.java7
-rw-r--r--server/src/main/java/com/vaadin/event/selection/MultiSelectionEvent.java31
-rw-r--r--server/src/main/java/com/vaadin/event/selection/MultiSelectionListener.java3
-rw-r--r--server/src/main/java/com/vaadin/event/selection/SelectionEvent.java2
-rw-r--r--server/src/main/java/com/vaadin/ui/components/grid/MultiSelectionModelImpl.java234
-rw-r--r--server/src/test/java/com/vaadin/event/selection/SelectionEventTest.java3
-rw-r--r--server/src/test/java/com/vaadin/tests/components/grid/GridMultiSelectionModelTest.java162
-rw-r--r--shared/src/main/java/com/vaadin/shared/ui/grid/MultiSelectionModelState.java33
-rw-r--r--uitest/src/main/java/com/vaadin/tests/components/grid/GridMultiSelectionOnInit.java18
-rw-r--r--uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java63
-rw-r--r--uitest/src/test/java/com/vaadin/tests/components/grid/GridDisabledMultiselectTest.java10
-rw-r--r--uitest/src/test/java/com/vaadin/tests/components/grid/GridMultiSelectionOnInitTest.java8
-rw-r--r--uitest/src/test/java/com/vaadin/tests/components/grid/GridSelectAllTest.java201
-rw-r--r--uitest/src/test/java/com/vaadin/tests/components/grid/GridSelectionTest.java52
-rw-r--r--uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridBasicSelectionTest.java84
-rw-r--r--uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridBasicsTest.java35
21 files changed, 1117 insertions, 267 deletions
diff --git a/client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java b/client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java
index bcae476cf3..7d906fc4af 100644
--- a/client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java
+++ b/client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java
@@ -151,7 +151,6 @@ public class GridConnector extends AbstractListingConnector
// Default selection style is space key.
spaceSelectHandler = new SpaceSelectHandler<>(getWidget());
- clickSelectHandler = new ClickSelectHandler<>(getWidget());
getWidget().addSortHandler(this::handleSortEvent);
getWidget().setRowStyleGenerator(rowRef -> {
JsonObject json = rowRef.getRow();
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 7b421be15b..b24cb54e63 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
@@ -15,21 +15,37 @@
*/
package com.vaadin.client.connectors.grid;
+import java.util.Optional;
+
+import com.google.gwt.event.shared.HandlerRegistration;
import com.vaadin.client.ServerConnector;
+import com.vaadin.client.annotations.OnStateChange;
+import com.vaadin.client.data.DataSource;
+import com.vaadin.client.data.DataSource.RowHandle;
import com.vaadin.client.extensions.AbstractExtensionConnector;
import com.vaadin.client.renderers.Renderer;
+import com.vaadin.client.widget.grid.events.SelectAllEvent;
import com.vaadin.client.widget.grid.selection.MultiSelectionRenderer;
import com.vaadin.client.widget.grid.selection.SelectionModel;
import com.vaadin.client.widget.grid.selection.SelectionModelWithSelectionColumn;
import com.vaadin.client.widgets.Grid;
+import com.vaadin.client.widgets.Grid.SelectionColumn;
+import com.vaadin.shared.Range;
import com.vaadin.shared.data.DataCommunicatorConstants;
import com.vaadin.shared.data.selection.GridMultiSelectServerRpc;
import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.grid.MultiSelectionModelState;
import elemental.json.JsonObject;
/**
* Connector for server side multiselection model implementation.
+ * <p>
+ * This selection model displays a selection column {@link SelectionColumn} as
+ * the first column of the grid.
+ * <p>
+ * Implementation detail: The Grid selection is updated immediately on client
+ * side, without waiting for the server response.
*
* @author Vaadin Ltd
*
@@ -39,6 +55,10 @@ import elemental.json.JsonObject;
@Connect(com.vaadin.ui.components.grid.MultiSelectionModelImpl.class)
public class MultiSelectionModelConnector extends AbstractExtensionConnector {
+ private HandlerRegistration selectAllHandler;
+ private HandlerRegistration dataAvailable;
+ private Range availableRows;
+
/**
* Client side multiselection model implementation.
*/
@@ -54,27 +74,37 @@ public class MultiSelectionModelConnector extends AbstractExtensionConnector {
@Override
public void select(JsonObject item) {
+ updateRowSelected(getGrid().getDataSource().getHandle(item), true);
+
getRpcProxy(GridMultiSelectServerRpc.class)
.select(item.getString(DataCommunicatorConstants.KEY));
}
@Override
public void deselect(JsonObject item) {
- // handled by diffstate
+ if (isAllSelected()) {
+ // handled by diffstate
+ getState().allSelected = false;
+ getGrid().getSelectionColumn().get().getSelectAllCheckBox()
+ .ifPresent(cb -> cb.setValue(false, false));
+ }
+ updateRowSelected(getGrid().getDataSource().getHandle(item), false);
+
getRpcProxy(GridMultiSelectServerRpc.class)
.deselect(item.getString(DataCommunicatorConstants.KEY));
}
@Override
public void deselectAll() {
- // TODO Will be added in a separate patch
- throw new UnsupportedOperationException(
- "Deselect all not supported.");
+ // handled by diffstate
+ updateAllRowsSelected(false);
+ getState().allSelected = false;
+ getRpcProxy(GridMultiSelectServerRpc.class).deselectAll();
}
@Override
public boolean isSelected(JsonObject item) {
- return SelectionModel.isItemSelected(item);
+ return MultiSelectionModelConnector.this.isSelected(item);
}
}
@@ -82,6 +112,19 @@ public class MultiSelectionModelConnector extends AbstractExtensionConnector {
@Override
protected void extend(ServerConnector target) {
getGrid().setSelectionModel(new MultiSelectionModel());
+ // capture current rows so that can show selection update immediately
+ dataAvailable = getGrid().addDataAvailableHandler(
+ event -> availableRows = event.getAvailableRows());
+ }
+
+ @Override
+ public void onUnregister() {
+ super.onUnregister();
+
+ dataAvailable.removeHandler();
+ if (selectAllHandler != null) {
+ selectAllHandler.removeHandler();
+ }
}
@Override
@@ -89,6 +132,11 @@ public class MultiSelectionModelConnector extends AbstractExtensionConnector {
return (GridConnector) super.getParent();
}
+ @Override
+ public MultiSelectionModelState getState() {
+ return (MultiSelectionModelState) super.getState();
+ }
+
/**
* Shorthand for fetching the grid this selection model is bound to.
*
@@ -98,4 +146,126 @@ public class MultiSelectionModelConnector extends AbstractExtensionConnector {
return getParent().getWidget();
}
+ @OnStateChange({ "selectAllCheckBoxVisible", "allSelected" })
+ void onSelectAllCheckboxStateUpdates() {
+ // in case someone wants to override this, moved the actual updating to
+ // a protected method
+ updateSelectAllCheckBox();
+ }
+
+ /**
+ * Called whenever there has been a state update for select all checkbox
+ * visibility or all have been selected or deselected.
+ */
+ protected void updateSelectAllCheckBox() {
+ final boolean selectAllCheckBoxVisible = getState().selectAllCheckBoxVisible;
+ if (selectAllCheckBoxVisible && selectAllHandler == null) {
+ selectAllHandler = getGrid()
+ .addSelectAllHandler(this::onSelectAllEvent);
+ } else if (!selectAllCheckBoxVisible && selectAllHandler != null) {
+ selectAllHandler.removeHandler();
+ selectAllHandler = null;
+ }
+ Optional<Grid<JsonObject>.SelectionColumn> selectionColumn = getGrid()
+ .getSelectionColumn();
+
+ // if someone extends this selection model and doesn't use the selection
+ // column, the select all checkbox is not there either
+ if (selectionColumn.isPresent()) {
+ selectionColumn.get()
+ .setSelectAllCheckBoxVisible(selectAllCheckBoxVisible);
+ selectionColumn.get().getSelectAllCheckBox()
+ .ifPresent(checkbox -> checkbox
+ .setValue(getState().allSelected, false));
+ }
+ }
+
+ /**
+ * Returns whether all items are selected or not.
+ *
+ * @return {@code true} if all items are selected, {@code false} if not
+ */
+ protected boolean isAllSelected() {
+ return getState().selectAllCheckBoxVisible && getState().allSelected;
+ }
+
+ /**
+ * Handler for selecting / deselecting all grid rows.
+ *
+ * @param event
+ * the select all event from grid
+ */
+ protected void onSelectAllEvent(SelectAllEvent<JsonObject> event) {
+ final boolean allSelected = event.isAllSelected();
+ final boolean wasAllSelected = isAllSelected();
+ assert allSelected != wasAllSelected : "Grid Select All CheckBox had invalid state";
+
+ if (allSelected && !wasAllSelected) {
+ getState().allSelected = true;
+ updateAllRowsSelected(true);
+ getRpcProxy(GridMultiSelectServerRpc.class).selectAll();
+ } else if (!allSelected && wasAllSelected) {
+ getState().allSelected = false;
+ updateAllRowsSelected(false);
+ getRpcProxy(GridMultiSelectServerRpc.class).deselectAll();
+ }
+ }
+
+ /**
+ * Update selection for all grid rows.
+ *
+ * @param selected
+ * {@code true} for marking all rows selected, {@code false} for
+ * not selected
+ */
+ protected void updateAllRowsSelected(boolean selected) {
+ if (availableRows != null) {
+ DataSource<JsonObject> dataSource = getGrid().getDataSource();
+ for (int i = availableRows.getStart(); i < availableRows
+ .getEnd(); ++i) {
+ final JsonObject row = dataSource.getRow(i);
+ if (row != null) {
+ RowHandle<JsonObject> handle = dataSource.getHandle(row);
+ updateRowSelected(handle, selected);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns whether the given item selected in grid or not.
+ *
+ * @param item
+ * the item to check
+ * @return {@code true} if selected {@code false} if not
+ */
+ protected boolean isSelected(JsonObject item) {
+ return getState().allSelected || SelectionModel.isItemSelected(item);
+ }
+
+ /**
+ * Marks the given row to be selected or deselected. Returns true if the
+ * value actually changed.
+ * <p>
+ * Note: If selection model is in batch select state, the row will be pinned
+ * on select.
+ *
+ * @param row
+ * row handle
+ * @param selected
+ * {@code true} if row should be selected; {@code false} if not
+ */
+ protected void updateRowSelected(RowHandle<JsonObject> row,
+ boolean selected) {
+ boolean itemWasMarkedSelected = SelectionModel
+ .isItemSelected(row.getRow());
+ if (selected && !itemWasMarkedSelected) {
+ row.getRow().put(DataCommunicatorConstants.SELECTED, true);
+ } else if (!selected && itemWasMarkedSelected) {
+ row.getRow().remove(DataCommunicatorConstants.SELECTED);
+ }
+
+ row.updateRow();
+ }
+
}
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 33a6d9d9b6..aba6d906b3 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
@@ -17,6 +17,7 @@ package com.vaadin.client.connectors.grid;
import com.vaadin.client.ServerConnector;
import com.vaadin.client.extensions.AbstractExtensionConnector;
+import com.vaadin.client.widget.grid.selection.ClickSelectHandler;
import com.vaadin.client.widget.grid.selection.SelectionModel;
import com.vaadin.shared.data.DataCommunicatorConstants;
import com.vaadin.shared.data.selection.SelectionServerRpc;
@@ -34,6 +35,8 @@ import elemental.json.JsonObject;
@Connect(com.vaadin.ui.components.grid.SingleSelectionModelImpl.class)
public class SingleSelectionModelConnector extends AbstractExtensionConnector {
+ private ClickSelectHandler clickSelectHandler;
+
@Override
protected void extend(ServerConnector target) {
getParent().getWidget()
@@ -62,6 +65,15 @@ public class SingleSelectionModelConnector extends AbstractExtensionConnector {
}
});
+ clickSelectHandler = new ClickSelectHandler<>(getParent().getWidget());
+ }
+
+ @Override
+ public void onUnregister() {
+ super.onUnregister();
+ if (clickSelectHandler != null) {
+ clickSelectHandler.removeHandler();
+ }
}
@Override
diff --git a/client/src/main/java/com/vaadin/client/widget/grid/events/SelectAllEvent.java b/client/src/main/java/com/vaadin/client/widget/grid/events/SelectAllEvent.java
index 25ce090d6e..f0c2a379dc 100644
--- a/client/src/main/java/com/vaadin/client/widget/grid/events/SelectAllEvent.java
+++ b/client/src/main/java/com/vaadin/client/widget/grid/events/SelectAllEvent.java
@@ -20,24 +20,53 @@ import com.vaadin.client.widget.grid.selection.SelectionModel;
/**
* A select all event, fired by the Grid when it needs all rows in data source
- * to be selected.
+ * to be selected, OR when all rows have been selected and are now deselected.
*
* @since 7.4
* @author Vaadin Ltd
+ * @param <T>
+ * the type of the rows in grid
*/
public class SelectAllEvent<T> extends GwtEvent<SelectAllHandler<T>> {
/**
* Handler type.
*/
- private final static Type<SelectAllHandler<?>> TYPE = new Type<>();;
+ private static final Type<SelectAllHandler<?>> TYPE = new Type<>();;
- private SelectionModel selectionModel;
+ private final SelectionModel<T> selectionModel;
+ private final boolean allSelected;
- public SelectAllEvent(SelectionModel selectionModel) {
+ /**
+ * Constructs a new select all event when all rows in grid are selected.
+ *
+ * @param selectionModel
+ * the selection model in use
+ */
+ public SelectAllEvent(SelectionModel<T> selectionModel) {
+ this(selectionModel, true);
+ }
+
+ /**
+ *
+ *
+ * @param selectionModel
+ * the selection model in use
+ * @param allSelected
+ * {@code true} for all selected, {@code false} for all
+ * deselected
+ */
+ public SelectAllEvent(SelectionModel<T> selectionModel,
+ boolean allSelected) {
this.selectionModel = selectionModel;
+ this.allSelected = allSelected;
}
+ /**
+ * Gets the type of the handlers for this event.
+ *
+ * @return the handler type
+ */
public static final Type<SelectAllHandler<?>> getType() {
return TYPE;
}
@@ -53,7 +82,23 @@ public class SelectAllEvent<T> extends GwtEvent<SelectAllHandler<T>> {
handler.onSelectAll(this);
}
- public SelectionModel getSelectionModel() {
+ /**
+ * The selection model in use.
+ *
+ * @return the selection model
+ */
+ public SelectionModel<T> getSelectionModel() {
return selectionModel;
}
+
+ /**
+ * Returns whether all the rows were selected, or deselected. Deselection
+ * can only happen if all rows were previously selected.
+ *
+ * @return {@code true} for selecting all rows, or {@code false} for
+ * deselecting all rows
+ */
+ public boolean isAllSelected() {
+ return allSelected;
+ }
}
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 97775aa482..afed21b045 100644
--- a/client/src/main/java/com/vaadin/client/widgets/Grid.java
+++ b/client/src/main/java/com/vaadin/client/widgets/Grid.java
@@ -26,6 +26,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.logging.Level;
@@ -56,8 +57,6 @@ import com.google.gwt.event.dom.client.KeyEvent;
import com.google.gwt.event.dom.client.MouseEvent;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
-import com.google.gwt.event.logical.shared.ValueChangeEvent;
-import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.touch.client.Point;
import com.google.gwt.user.client.DOM;
@@ -549,10 +548,12 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
return join(columns);
}
- private CELLTYPE getMergedCellForColumn(
- Column<?, ?> column) {
- for (Entry<CELLTYPE, Set<Column<?, ?>>> entry : cellGroups.entrySet()) {
- if (entry.getValue().contains(column)) return entry.getKey();
+ private CELLTYPE getMergedCellForColumn(Column<?, ?> column) {
+ for (Entry<CELLTYPE, Set<Column<?, ?>>> entry : cellGroups
+ .entrySet()) {
+ if (entry.getValue().contains(column)) {
+ return entry.getKey();
+ }
}
return null;
}
@@ -563,7 +564,8 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
cell.setColspan(1);
}
// Set colspan for grouped cells
- for (Entry<CELLTYPE, Set<Column<?, ?>>> entry : cellGroups.entrySet()) {
+ for (Entry<CELLTYPE, Set<Column<?, ?>>> entry : cellGroups
+ .entrySet()) {
CELLTYPE mergedCell = entry.getKey();
if (!checkMergedCellIsContinuous(entry.getValue())) {
// on error simply break the merged cell
@@ -2835,6 +2837,8 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
private boolean initDone = false;
private boolean selected = false;
private CheckBox selectAllCheckBox;
+ private boolean selectAllCheckBoxVisible;
+ private HeaderCell selectionCell;
SelectionColumn(final Renderer<Boolean> selectColumnRenderer) {
super(selectColumnRenderer);
@@ -2853,68 +2857,27 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
@Override
protected void setDefaultHeaderContent(HeaderCell selectionCell) {
- final SelectionModel<T> model = getSelectionModel();
- final boolean shouldSelectAllCheckBoxBeShown = getHandlerCount(
- SelectAllEvent.getType()) > 0;
+ this.selectionCell = selectionCell;
- if (selectAllCheckBox == null && shouldSelectAllCheckBoxBeShown) {
+ // there is no checkbox yet -> create it
+ if (selectAllCheckBox == null) {
selectAllCheckBox = GWT.create(CheckBox.class);
selectAllCheckBox.setStylePrimaryName(
getStylePrimaryName() + SELECT_ALL_CHECKBOX_CLASSNAME);
- selectAllCheckBox.addValueChangeHandler(
- new ValueChangeHandler<Boolean>() {
-
- @Override
- public void onValueChange(
- ValueChangeEvent<Boolean> event) {
- if (event.getValue()) {
- fireEvent(new SelectAllEvent<>(model));
- selected = true;
- } else {
- model.deselectAll();
- selected = false;
- }
- }
- });
+ selectAllCheckBox.addValueChangeHandler(event -> {
+ selected = event.getValue();
+ fireEvent(new SelectAllEvent<>(getSelectionModel(),
+ selected));
+ });
selectAllCheckBox.setValue(selected);
- addHeaderClickHandler(new HeaderClickHandler() {
- @Override
- public void onClick(GridClickEvent event) {
- CellReference<?> targetCell = event.getTargetCell();
- int defaultRowIndex = getHeader().getRows()
- .indexOf(getDefaultHeaderRow());
-
- if (targetCell.getColumnIndex() == 0 && targetCell
- .getRowIndex() == defaultRowIndex) {
- selectAllCheckBox.setValue(
- !selectAllCheckBox.getValue(), true);
- }
- }
- });
+ addHeaderClickHandler(this::onHeaderClickEvent);
// Select all with space when "select all" cell is active
- addHeaderKeyUpHandler(new HeaderKeyUpHandler() {
- @Override
- public void onKeyUp(GridKeyUpEvent event) {
- if (event.getNativeKeyCode() != KeyCodes.KEY_SPACE) {
- return;
- }
- HeaderRow targetHeaderRow = getHeader()
- .getRow(event.getFocusedCell().getRowIndex());
- if (!targetHeaderRow.isDefault()) {
- return;
- }
- if (event.getFocusedCell()
- .getColumn() == SelectionColumn.this) {
- // Send events to ensure state is updated
- selectAllCheckBox.setValue(
- !selectAllCheckBox.getValue(), true);
- }
- }
- });
- } else if (selectAllCheckBox != null
- && !shouldSelectAllCheckBoxBeShown) {
+ addHeaderKeyUpHandler(this::onHeaderKeyUpEvent);
+
+ } else { // checkbox exists, but default header row has changed ->
+ // clear rows
for (HeaderRow row : header.getRows()) {
if (row.getCell(this)
.getType() == GridStaticCellType.WIDGET) {
@@ -2924,7 +2887,8 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
}
}
- selectionCell.setWidget(selectAllCheckBox);
+ // attach the checkbox to default row depending on visibility
+ doSetSelectAllCheckBoxVisible();
}
@Override
@@ -3005,6 +2969,87 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
public void onEnabled(boolean enabled) {
setEnabled(enabled);
}
+
+ /**
+ * Sets the select all checkbox visible in the default header row for
+ * selection column.
+ *
+ * @param selectAllCheckBoxVisible
+ * {@code true} for visible, {@code false} for not
+ */
+ public void setSelectAllCheckBoxVisible(
+ boolean selectAllCheckBoxVisible) {
+ if (this.selectAllCheckBoxVisible != selectAllCheckBoxVisible) {
+ this.selectAllCheckBoxVisible = selectAllCheckBoxVisible;
+ doSetSelectAllCheckBoxVisible();
+ }
+ }
+
+ /**
+ * Returns whether the select all checkbox is visible or not.
+ *
+ * @return {@code true} for visible, {@code false} for not
+ */
+ public boolean isSelectAllCheckBoxVisible() {
+ return selectAllCheckBoxVisible;
+ }
+
+ /**
+ * Returns the select all checkbox, which is present in the default
+ * header if the used selection model is of type
+ * {@link SelectionModelWithSelectionColumn}.
+ *
+ * To handle select all, add {@link SelectAllHandler} the grid with
+ * {@link #addSelectAllHandler(SelectAllHandler)}.
+ *
+ * @return the select all checkbox, or an empty optional if not in use
+ */
+ public Optional<CheckBox> getSelectAllCheckBox() {
+ return Optional.ofNullable(selectionColumn == null ? null
+ : selectionColumn.selectAllCheckBox);
+ }
+
+ /**
+ * Sets the select all checkbox visible or hidden.
+ */
+ protected void doSetSelectAllCheckBoxVisible() {
+ assert selectAllCheckBox != null : "Select All Checkbox has not been created for selection column.";
+ assert selectionCell != null : "Default header cell for selection column not been set.";
+
+ if (selectAllCheckBoxVisible) {
+ selectionCell.setWidget(selectAllCheckBox);
+ } else {
+ selectAllCheckBox.removeFromParent();
+ selectionCell.setText("");
+ }
+ }
+
+ private void onHeaderClickEvent(GridClickEvent event) {
+ 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) {
+ return;
+ }
+ HeaderRow targetHeaderRow = getHeader()
+ .getRow(event.getFocusedCell().getRowIndex());
+ if (!targetHeaderRow.isDefault()) {
+ return;
+ }
+ if (event.getFocusedCell().getColumn() == SelectionColumn.this) {
+ // Send events to ensure state is updated
+ selectAllCheckBox.setValue(!selectAllCheckBox.getValue(), true);
+ }
+ }
+
}
/**
@@ -7557,8 +7602,6 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
/**
* Sets the current selection model.
- * <p>
- * This function will call {@link SelectionModel#setGrid(Grid)}.
*
* @param selectionModel
* a selection model implementation.
@@ -7755,6 +7798,10 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
/**
* Register a GWT event handler for a select all event. This handler gets
* called whenever Grid needs all rows selected.
+ * <p>
+ * In case the select all checkbox is not visible in the
+ * {@link SelectionColumn}, it will be come visible after adding the
+ * handler.
*
* @param handler
* a select all event handler
@@ -7762,7 +7809,9 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
*/
public HandlerRegistration addSelectAllHandler(
SelectAllHandler<T> handler) {
- return addHandler(handler, SelectAllEvent.getType());
+ HandlerRegistration registration = addHandler(handler,
+ SelectAllEvent.getType());
+ return registration;
}
/**
@@ -7775,7 +7824,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
*
* @param handler
* a data available event handler
- * @return the registartion for the event
+ * @return the registration for the event
*/
public HandlerRegistration addDataAvailableHandler(
final DataAvailableHandler handler) {
@@ -8845,4 +8894,13 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
return null;
}
+ /**
+ * Returns the selection column for the grid if the selection model is of
+ * type {@link SelectionModelWithSelectionColumn}.
+ *
+ * @return the select all checkbox, or an empty optional if not in use
+ */
+ public Optional<SelectionColumn> getSelectionColumn() {
+ return Optional.ofNullable(selectionColumn);
+ }
}
diff --git a/server/src/main/java/com/vaadin/data/SelectionModel.java b/server/src/main/java/com/vaadin/data/SelectionModel.java
index cf4fb846b6..310f79f7d0 100644
--- a/server/src/main/java/com/vaadin/data/SelectionModel.java
+++ b/server/src/main/java/com/vaadin/data/SelectionModel.java
@@ -196,12 +196,9 @@ public interface SelectionModel<T> extends Serializable {
}
/**
- * Deselects all currently selected items.
+ * Selects all available the items.
*/
- @Override
- public default void deselectAll() {
- updateSelection(Collections.emptySet(), getSelectedItems());
- }
+ public void selectAll();
}
/**
diff --git a/server/src/main/java/com/vaadin/event/selection/MultiSelectionEvent.java b/server/src/main/java/com/vaadin/event/selection/MultiSelectionEvent.java
index 7718b5a1a6..e08ba491af 100644
--- a/server/src/main/java/com/vaadin/event/selection/MultiSelectionEvent.java
+++ b/server/src/main/java/com/vaadin/event/selection/MultiSelectionEvent.java
@@ -16,6 +16,7 @@
package com.vaadin.event.selection;
import java.util.Collections;
+import java.util.LinkedHashSet;
import java.util.Optional;
import java.util.Set;
@@ -100,6 +101,36 @@ public class MultiSelectionEvent<T> extends ValueChangeEvent<Set<T>>
return Collections.unmodifiableSet(oldSelection);
}
+ /**
+ * Gets the items that were removed from selection.
+ * <p>
+ * This is just a convenience method for checking what was previously
+ * selected in {@link #getOldSelection()} but not selected anymore in
+ * {@link #getNewSelection()}.
+ *
+ * @return the items that were removed from selection
+ */
+ public Set<T> getRemovedSelection() {
+ LinkedHashSet<T> copy = new LinkedHashSet<>(oldSelection);
+ copy.removeAll(getNewSelection());
+ return copy;
+ }
+
+ /**
+ * Gets the items that were added to selection.
+ * <p>
+ * This is just a convenience method for checking what is new selected in
+ * {@link #getNewSelection()} and wasn't selected in
+ * {@link #getOldSelection()}.
+ *
+ * @return the items that were removed from selection
+ */
+ public Set<T> getAddedSelection() {
+ LinkedHashSet<T> copy = new LinkedHashSet<>(getValue());
+ copy.removeAll(oldSelection);
+ return copy;
+ }
+
@Override
public Optional<T> getFirstSelected() {
return getValue().stream().findFirst();
diff --git a/server/src/main/java/com/vaadin/event/selection/MultiSelectionListener.java b/server/src/main/java/com/vaadin/event/selection/MultiSelectionListener.java
index d8005a396c..b7d7ae4b8b 100644
--- a/server/src/main/java/com/vaadin/event/selection/MultiSelectionListener.java
+++ b/server/src/main/java/com/vaadin/event/selection/MultiSelectionListener.java
@@ -19,8 +19,7 @@ import java.io.Serializable;
import java.util.function.Consumer;
/**
- * Listens to changes from a
- * {@link com.vaadin.data.SelectionModel.Multi}.
+ * Listens to changes from a {@link com.vaadin.data.SelectionModel.Multi}.
*
* @author Vaadin Ltd
*
diff --git a/server/src/main/java/com/vaadin/event/selection/SelectionEvent.java b/server/src/main/java/com/vaadin/event/selection/SelectionEvent.java
index 28b3fd4461..7240886f2e 100644
--- a/server/src/main/java/com/vaadin/event/selection/SelectionEvent.java
+++ b/server/src/main/java/com/vaadin/event/selection/SelectionEvent.java
@@ -35,7 +35,7 @@ public interface SelectionEvent<T> extends Serializable {
* <p>
* This is the same as {@link SingleSelectionChange#getSelectedItem()} in
* case of single selection and the first selected item from
- * {@link MultiSelectionEvent#getNewSelection()} in case of multi selection.
+ * {@link MultiSelectionChangeEvent#getNewSelection()} in case of multi selection.
*
* @return the first selected item.
*/
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 286edd5f2b..70a056f34c 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
@@ -23,12 +23,16 @@ import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import com.vaadin.event.selection.MultiSelectionEvent;
import com.vaadin.event.selection.MultiSelectionListener;
+import com.vaadin.server.data.DataProvider;
+import com.vaadin.server.data.Query;
import com.vaadin.shared.Registration;
import com.vaadin.shared.data.DataCommunicatorConstants;
import com.vaadin.shared.data.selection.GridMultiSelectServerRpc;
+import com.vaadin.shared.ui.grid.MultiSelectionModelState;
import com.vaadin.ui.Grid;
import com.vaadin.ui.Grid.AbstractGridExtension;
import com.vaadin.ui.Grid.MultiSelectionModel;
@@ -42,6 +46,9 @@ import elemental.json.JsonObject;
* <p>
* Shows a column of checkboxes as the first column of grid. Each checkbox
* triggers the selection for that row.
+ * <p>
+ * Implementation detail: The Grid selection is updated immediately after user
+ * selection on client side, without waiting for the server response.
*
* @author Vaadin Ltd.
* @since 8.0
@@ -52,6 +59,39 @@ import elemental.json.JsonObject;
public class MultiSelectionModelImpl<T> extends AbstractGridExtension<T>
implements MultiSelectionModel<T> {
+ /**
+ * State for showing the select all checkbox in the grid's default header
+ * row for the selection column.
+ * <p>
+ * Default value is {@link #DEFAULT}, which means that the select all is
+ * only visible if an in-memory data provider is used
+ * {@link DataSource#isInMemory()}.
+ */
+ public enum SelectAllCheckBoxVisible {
+ /**
+ * Shows the select all checkbox, regardless of data provider used.
+ * <p>
+ * <b>For a lazy data provider, selecting all will result in to all rows
+ * being fetched from backend to application memory!</b>
+ */
+ VISIBLE,
+ /**
+ * Never shows the select all checkbox, regardless of data provider
+ * used.
+ */
+ HIDDEN,
+ /**
+ * By default select all checkbox depends on the grid's dataprovider.
+ * <ul>
+ * <li>Visible, if the data provider is in-memory</li>
+ * <li>Hidden, if the data provider is NOT in-memory (lazy)</li>
+ * </ul>
+ *
+ * @see DataProvider#isInMemory()}.
+ */
+ DEFAULT;
+ }
+
private class GridMultiSelectServerRpcImpl
implements GridMultiSelectServerRpc {
@@ -64,21 +104,25 @@ public class MultiSelectionModelImpl<T> extends AbstractGridExtension<T>
@Override
public void deselect(String key) {
+ if (getState(false).allSelected) {
+ // updated right away on client side
+ getState(false).allSelected = false;
+ getUI().getConnectorTracker()
+ .getDiffState(MultiSelectionModelImpl.this)
+ .put("allSelected", false);
+ }
MultiSelectionModelImpl.this.updateSelection(Collections.emptySet(),
new LinkedHashSet<>(Arrays.asList(getData(key))), true);
}
@Override
public void selectAll() {
- // TODO will be added in another patch
- throw new UnsupportedOperationException("Select all not supported");
+ onSelectAll(true);
}
@Override
public void deselectAll() {
- // TODO will be added in another patch
- throw new UnsupportedOperationException(
- "Deelect all not supported");
+ onDeselectAll(true);
}
}
@@ -91,6 +135,8 @@ public class MultiSelectionModelImpl<T> extends AbstractGridExtension<T>
private Set<T> selection = new LinkedHashSet<>();
+ private SelectAllCheckBoxVisible selectAllCheckBoxVisible = SelectAllCheckBoxVisible.DEFAULT;
+
/**
* Constructs a new multiselection model for the given grid.
*
@@ -105,6 +151,113 @@ public class MultiSelectionModelImpl<T> extends AbstractGridExtension<T>
}
@Override
+ protected MultiSelectionModelState getState() {
+ return (MultiSelectionModelState) super.getState();
+ }
+
+ @Override
+ protected MultiSelectionModelState getState(boolean markAsDirty) {
+ return (MultiSelectionModelState) super.getState(markAsDirty);
+ }
+
+ /**
+ * Sets the select all checkbox visibility mode.
+ * <p>
+ * The default value is {@link SelectAllCheckBoxVisible#DEFAULT}, which
+ * means that the checkbox is only visible if the grid's data provider is
+ * in- memory.
+ *
+ * @param selectAllCheckBoxVisible
+ * the mode to use
+ * @see SelectAllCheckBoxVisible
+ */
+ public void setSelectAllCheckBoxVisible(
+ SelectAllCheckBoxVisible selectAllCheckBoxVisible) {
+ if (this.selectAllCheckBoxVisible != selectAllCheckBoxVisible) {
+ this.selectAllCheckBoxVisible = selectAllCheckBoxVisible;
+ markAsDirty();
+ }
+ }
+
+ /**
+ * Gets the current mode for the select all checkbox visibility.
+ *
+ * @return the select all checkbox visibility state
+ * @see SelectAllCheckBoxVisible
+ * @see #isSelectAllCheckBoxVisible()
+ */
+ public SelectAllCheckBoxVisible getSelectAllCheckBoxVisible() {
+ return selectAllCheckBoxVisible;
+ }
+
+ /**
+ * Returns whether the select all checkbox will be visible with the current
+ * setting of
+ * {@link #setSelectAllCheckBoxVisible(SelectAllCheckBoxVisible)}.
+ *
+ * @return {@code true} if the checkbox will be visible with the current
+ * settings
+ * @see SelectAllCheckBoxVisible
+ * @see #setSelectAllCheckBoxVisible(SelectAllCheckBoxVisible)
+ */
+ public boolean isSelectAllCheckBoxVisible() {
+ updateCanSelectAll();
+ return getState(false).selectAllCheckBoxVisible;
+ }
+
+ /**
+ * Returns whether all items are selected or not.
+ * <p>
+ * This is only {@code true} if user has selected all rows with the select
+ * all checkbox on client side, or if {@link #selectAll()} has been used
+ * from server side.
+ *
+ * @return {@code true} if all selected, {@code false} if not
+ */
+ public boolean isAllSelected() {
+ return getState(false).allSelected;
+ }
+
+ @Override
+ public boolean isSelected(T item) {
+ return isAllSelected()
+ || com.vaadin.ui.Grid.MultiSelectionModel.super.isSelected(
+ item);
+ }
+
+ @Override
+ public void beforeClientResponse(boolean initial) {
+ super.beforeClientResponse(initial);
+ updateCanSelectAll();
+ }
+
+ /**
+ * Controls whether the select all checkbox is visible in the grid default
+ * header, or not.
+ * <p>
+ * This is updated as a part of {@link #beforeClientResponse(boolean)},
+ * since the data provider for grid can be changed on the fly.
+ *
+ * @see SelectAllCheckBoxVisible
+ */
+ protected void updateCanSelectAll() {
+ switch (selectAllCheckBoxVisible) {
+ case VISIBLE:
+ getState(false).selectAllCheckBoxVisible = true;
+ break;
+ case HIDDEN:
+ getState(false).selectAllCheckBoxVisible = false;
+ break;
+ case DEFAULT:
+ getState(false).selectAllCheckBoxVisible = grid.getDataProvider()
+ .isInMemory();
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
public void remove() {
updateSelection(Collections.emptySet(), getSelectedItems(), false);
@@ -145,6 +298,16 @@ public class MultiSelectionModelImpl<T> extends AbstractGridExtension<T>
updateSelection(addedItems, removedItems, false);
}
+ @Override
+ public void selectAll() {
+ onSelectAll(false);
+ }
+
+ @Override
+ public void deselectAll() {
+ onDeselectAll(false);
+ }
+
/**
* Gets a wrapper for using this grid as a multiselect in a binder.
*
@@ -225,6 +388,59 @@ public class MultiSelectionModelImpl<T> extends AbstractGridExtension<T>
}
/**
+ * Triggered when the user checks the select all checkbox.
+ *
+ * @param userOriginated
+ * {@code true} if originated from client side by user
+ */
+ protected void onSelectAll(boolean userOriginated) {
+ if (userOriginated) {
+ verifyUserCanSelectAll();
+ // all selected state has been updated in client side already
+ getState(false).allSelected = true;
+ getUI().getConnectorTracker().getDiffState(this).put("allSelected",
+ true);
+ } else {
+ getState().allSelected = true;
+ }
+
+ DataProvider<T, ?> dataSource = grid.getDataProvider();
+ // this will fetch everything from backend
+ Stream<T> stream = dataSource.fetch(new Query<>());
+ LinkedHashSet<T> allItems = new LinkedHashSet<>();
+ stream.forEach(allItems::add);
+ updateSelection(allItems, Collections.emptySet(), userOriginated);
+ }
+
+ /**
+ * Triggered when the user unchecks the select all checkbox.
+ *
+ * @param userOriginated
+ * {@code true} if originated from client side by user
+ */
+ protected void onDeselectAll(boolean userOriginated) {
+ if (userOriginated) {
+ verifyUserCanSelectAll();
+ // all selected state has been update in client side already
+ getState(false).allSelected = false;
+ getUI().getConnectorTracker().getDiffState(this).put("allSelected",
+ false);
+ } else {
+ getState().allSelected = false;
+ }
+
+ updateSelection(Collections.emptySet(), new LinkedHashSet<>(selection),
+ userOriginated);
+ }
+
+ private void verifyUserCanSelectAll() {
+ if (!getState(false).selectAllCheckBoxVisible) {
+ throw new IllegalStateException(
+ "Cannot select all from client since select all checkbox should not be visible");
+ }
+ }
+
+ /**
* Updates the selection by adding and removing the given items.
* <p>
* All selection updates should go through this method, since it handles
@@ -252,10 +468,18 @@ public class MultiSelectionModelImpl<T> extends AbstractGridExtension<T>
return;
}
+ // update allSelected for server side selection updates
+ if (getState(false).allSelected && !removedItems.isEmpty()
+ && !userOriginated) {
+ getState().allSelected = false;
+ }
+
doUpdateSelection(set -> {
// order of add / remove does not matter since no duplicates
set.removeAll(removedItems);
set.addAll(addedItems);
+
+ // refresh method is NOOP for items that are not present client side
removedItems.forEach(grid.getDataCommunicator()::refresh);
addedItems.forEach(grid.getDataCommunicator()::refresh);
}, userOriginated);
diff --git a/server/src/test/java/com/vaadin/event/selection/SelectionEventTest.java b/server/src/test/java/com/vaadin/event/selection/SelectionEventTest.java
index 97a6ed03d1..8d3559642b 100644
--- a/server/src/test/java/com/vaadin/event/selection/SelectionEventTest.java
+++ b/server/src/test/java/com/vaadin/event/selection/SelectionEventTest.java
@@ -51,8 +51,7 @@ public class SelectionEventTest {
@SuppressWarnings({ "unchecked", "rawtypes" })
@Test
public void getFirstSelected_singleSelectEvent() {
- SingleSelectionEvent event = Mockito
- .mock(SingleSelectionEvent.class);
+ SingleSelectionEvent event = Mockito.mock(SingleSelectionEvent.class);
Mockito.doCallRealMethod().when(event).getFirstSelected();
Mockito.when(event.getSelectedItem()).thenReturn(Optional.of("foo"));
diff --git a/server/src/test/java/com/vaadin/tests/components/grid/GridMultiSelectionModelTest.java b/server/src/test/java/com/vaadin/tests/components/grid/GridMultiSelectionModelTest.java
index d7a087be54..4eb7170fed 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
@@ -16,6 +16,7 @@ import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.IntStream;
import org.easymock.Capture;
import org.junit.Assert;
@@ -23,14 +24,17 @@ 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.event.selection.MultiSelectionEvent;
+import com.vaadin.event.selection.MultiSelectionListener;
+import com.vaadin.server.data.BackEndDataProvider;
import com.vaadin.server.data.provider.bov.Person;
import com.vaadin.shared.Registration;
+import com.vaadin.tests.util.MockUI;
import com.vaadin.ui.Grid;
import com.vaadin.ui.Grid.GridSelectionModel;
+import com.vaadin.ui.UI;
import com.vaadin.ui.components.grid.MultiSelectionModelImpl;
+import com.vaadin.ui.components.grid.MultiSelectionModelImpl.SelectAllCheckBoxVisible;
import com.vaadin.ui.components.grid.SingleSelectionModelImpl;
import elemental.json.JsonObject;
@@ -116,7 +120,8 @@ public class GridMultiSelectionModelTest {
assertEquals(Arrays.asList("Foo", "Bar"), selectionChanges);
selectionChanges.clear();
- customGrid.setSelectionModel(new SingleSelectionModelImpl<>(customGrid));
+ customGrid
+ .setSelectionModel(new SingleSelectionModelImpl<>(customGrid));
assertFalse(customGrid.getSelectionModel().getFirstSelectedItem()
.isPresent());
assertEquals(Arrays.asList(), selectionChanges);
@@ -167,7 +172,8 @@ public class GridMultiSelectionModelTest {
// switch to single to cause event
customModel.generatedData.clear();
- customGrid.setSelectionModel(new SingleSelectionModelImpl<>(customGrid));
+ customGrid
+ .setSelectionModel(new SingleSelectionModelImpl<>(customGrid));
customGrid.getDataCommunicator().beforeClientResponse(false);
// changing selection model should trigger row updates, but the old
@@ -178,8 +184,8 @@ public class GridMultiSelectionModelTest {
@Test
public void select_gridWithStrings() {
Grid<String> gridWithStrings = new Grid<>();
- gridWithStrings
- .setSelectionModel(new MultiSelectionModelImpl<>(gridWithStrings));
+ gridWithStrings.setSelectionModel(
+ new MultiSelectionModelImpl<>(gridWithStrings));
gridWithStrings.setItems("Foo", "Bar", "Baz");
GridSelectionModel<String> model = gridWithStrings.getSelectionModel();
@@ -390,6 +396,39 @@ public class GridMultiSelectionModelTest {
}
@Test
+ public void selectAll() {
+ selectionModel.selectAll();
+
+ assertTrue(selectionModel.isAllSelected());
+ assertTrue(selectionModel.isSelected(PERSON_A));
+ assertTrue(selectionModel.isSelected(PERSON_B));
+ assertTrue(selectionModel.isSelected(PERSON_C));
+ assertEquals(Arrays.asList(PERSON_A, PERSON_B, PERSON_C),
+ currentSelectionCapture.getValue());
+ assertEquals(1, events.get());
+
+ selectionModel.deselectItems(PERSON_A, PERSON_C);
+
+ assertFalse(selectionModel.isAllSelected());
+ assertFalse(selectionModel.isSelected(PERSON_A));
+ assertTrue(selectionModel.isSelected(PERSON_B));
+ assertFalse(selectionModel.isSelected(PERSON_C));
+ assertEquals(Arrays.asList(PERSON_A, PERSON_B, PERSON_C),
+ oldSelectionCapture.getValue());
+
+ selectionModel.selectAll();
+
+ assertTrue(selectionModel.isAllSelected());
+ assertTrue(selectionModel.isSelected(PERSON_A));
+ assertTrue(selectionModel.isSelected(PERSON_B));
+ assertTrue(selectionModel.isSelected(PERSON_C));
+ assertEquals(Arrays.asList(PERSON_B, PERSON_A, PERSON_C),
+ currentSelectionCapture.getValue());
+ assertEquals(Arrays.asList(PERSON_B), oldSelectionCapture.getValue());
+ assertEquals(3, events.get());
+ }
+
+ @Test
public void updateSelection() {
selectionModel.updateSelection(asSet(PERSON_A), Collections.emptySet());
@@ -506,38 +545,129 @@ public class GridMultiSelectionModelTest {
@SuppressWarnings({ "serial" })
@Test
public void addValueChangeListener() {
- AtomicReference<SingleSelectionListener<String>> selectionListener = new AtomicReference<>();
+ AtomicReference<MultiSelectionListener<String>> selectionListener = new AtomicReference<>();
Registration registration = Mockito.mock(Registration.class);
Grid<String> grid = new Grid<>();
grid.setItems("foo", "bar");
String value = "foo";
- SingleSelectionModelImpl<String> select = new SingleSelectionModelImpl<String>(
+ MultiSelectionModelImpl<String> select = new MultiSelectionModelImpl<String>(
grid) {
@Override
public Registration addSelectionListener(
- SingleSelectionListener<String> listener) {
+ MultiSelectionListener<String> listener) {
selectionListener.set(listener);
return registration;
}
@Override
- public Optional<String> getSelectedItem() {
- return Optional.of(value);
+ public Set<String> getSelectedItems() {
+ return new LinkedHashSet<>(Arrays.asList(value));
}
};
- AtomicReference<ValueChangeEvent<?>> event = new AtomicReference<>();
+ AtomicReference<MultiSelectionEvent<String>> event = new AtomicReference<>();
Registration actualRegistration = select.addSelectionListener(evt -> {
Assert.assertNull(event.get());
event.set(evt);
});
Assert.assertSame(registration, actualRegistration);
- selectionListener.get().accept(new SingleSelectionEvent<>(grid,
- select.asSingleSelect(), true));
+ selectionListener.get().accept(new MultiSelectionEvent<>(grid,
+ select.asMultiSelect(), Collections.emptySet(), true));
Assert.assertEquals(grid, event.get().getComponent());
- Assert.assertEquals(value, event.get().getValue());
+ Assert.assertEquals(new LinkedHashSet<>(Arrays.asList(value)),
+ event.get().getValue());
Assert.assertTrue(event.get().isUserOriginated());
}
+
+ @Test
+ public void selectAllCheckboxVisible__inMemoryDataProvider() {
+ Grid<String> grid = new Grid<>();
+ UI ui = new MockUI();
+ ui.setContent(grid);
+
+ MultiSelectionModelImpl<String> model = new MultiSelectionModelImpl<>(
+ grid);
+ grid.setSelectionModel(model);
+
+ // no items yet, default data provider is empty not in memory one
+ Assert.assertFalse(model.isSelectAllCheckBoxVisible());
+ Assert.assertEquals(SelectAllCheckBoxVisible.DEFAULT,
+ model.getSelectAllCheckBoxVisible());
+
+ grid.setItems("Foo", "Bar", "Baz");
+
+ // in-memory container keeps default
+ Assert.assertTrue(model.isSelectAllCheckBoxVisible());
+ Assert.assertEquals(SelectAllCheckBoxVisible.DEFAULT,
+ model.getSelectAllCheckBoxVisible());
+
+ // change to explicit NO
+ model.setSelectAllCheckBoxVisible(SelectAllCheckBoxVisible.HIDDEN);
+
+ Assert.assertEquals(SelectAllCheckBoxVisible.HIDDEN,
+ model.getSelectAllCheckBoxVisible());
+ Assert.assertFalse(model.isSelectAllCheckBoxVisible());
+
+ // change to explicit YES
+ model.setSelectAllCheckBoxVisible(SelectAllCheckBoxVisible.VISIBLE);
+
+ Assert.assertEquals(SelectAllCheckBoxVisible.VISIBLE,
+ model.getSelectAllCheckBoxVisible());
+ Assert.assertTrue(model.isSelectAllCheckBoxVisible());
+ }
+
+ @Test
+ public void selectAllCheckboxVisible__lazyDataProvider() {
+ Grid<String> grid = new Grid<>();
+ UI ui = new MockUI();
+ ui.setContent(grid);
+
+ MultiSelectionModelImpl<String> model = new MultiSelectionModelImpl<>(
+ grid);
+ grid.setSelectionModel(model);
+
+ // no items yet, default data provider is empty not in memory one
+ Assert.assertFalse(model.isSelectAllCheckBoxVisible());
+ Assert.assertEquals(SelectAllCheckBoxVisible.DEFAULT,
+ model.getSelectAllCheckBoxVisible());
+
+ grid.setDataProvider(
+ new BackEndDataProvider<String, String>(
+ q -> IntStream
+ .range(q.getOffset(),
+ Math.max(q.getOffset() + q.getLimit()
+ + 1, 1000))
+ .mapToObj(i -> "Item " + i),
+ q -> 1000));
+
+ // not in-memory -> checkbox is hidden
+ Assert.assertFalse(model.isSelectAllCheckBoxVisible());
+ Assert.assertEquals(SelectAllCheckBoxVisible.DEFAULT,
+ model.getSelectAllCheckBoxVisible());
+
+ // change to explicit YES
+ model.setSelectAllCheckBoxVisible(SelectAllCheckBoxVisible.VISIBLE);
+
+ Assert.assertEquals(SelectAllCheckBoxVisible.VISIBLE,
+ model.getSelectAllCheckBoxVisible());
+ Assert.assertTrue(model.isSelectAllCheckBoxVisible());
+
+ // change to explicit NO
+ model.setSelectAllCheckBoxVisible(SelectAllCheckBoxVisible.HIDDEN);
+
+ Assert.assertEquals(SelectAllCheckBoxVisible.HIDDEN,
+ model.getSelectAllCheckBoxVisible());
+ Assert.assertFalse(model.isSelectAllCheckBoxVisible());
+
+ // change back to depends on data provider
+ model.setSelectAllCheckBoxVisible(
+ SelectAllCheckBoxVisible.DEFAULT);
+
+ Assert.assertFalse(model.isSelectAllCheckBoxVisible());
+ Assert.assertEquals(SelectAllCheckBoxVisible.DEFAULT,
+ model.getSelectAllCheckBoxVisible());
+
+ }
}
diff --git a/shared/src/main/java/com/vaadin/shared/ui/grid/MultiSelectionModelState.java b/shared/src/main/java/com/vaadin/shared/ui/grid/MultiSelectionModelState.java
new file mode 100644
index 0000000000..5d2a1c6094
--- /dev/null
+++ b/shared/src/main/java/com/vaadin/shared/ui/grid/MultiSelectionModelState.java
@@ -0,0 +1,33 @@
+/*
+ * 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.shared.ui.grid;
+
+import com.vaadin.shared.communication.SharedState;
+
+/**
+ * SharedState object for MultiSelectionModel.
+ *
+ * @since 8.0
+ * @author Vaadin Ltd
+ */
+public class MultiSelectionModelState extends SharedState {
+
+ /** Is the select all checkbox visible. */
+ public boolean selectAllCheckBoxVisible;
+ /** Select All -checkbox status. */
+ public boolean allSelected;
+
+}
diff --git a/uitest/src/main/java/com/vaadin/tests/components/grid/GridMultiSelectionOnInit.java b/uitest/src/main/java/com/vaadin/tests/components/grid/GridMultiSelectionOnInit.java
index 2b1e78d323..356935f7b8 100644
--- a/uitest/src/main/java/com/vaadin/tests/components/grid/GridMultiSelectionOnInit.java
+++ b/uitest/src/main/java/com/vaadin/tests/components/grid/GridMultiSelectionOnInit.java
@@ -15,11 +15,15 @@
*/
package com.vaadin.tests.components.grid;
+import java.util.Arrays;
+
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.Button;
import com.vaadin.ui.Grid;
+import com.vaadin.ui.RadioButtonGroup;
import com.vaadin.ui.components.grid.MultiSelectionModelImpl;
+import com.vaadin.ui.components.grid.MultiSelectionModelImpl.SelectAllCheckBoxVisible;
public class GridMultiSelectionOnInit extends AbstractTestUI {
@@ -28,7 +32,9 @@ public class GridMultiSelectionOnInit extends AbstractTestUI {
final Grid<String> grid = new Grid<>();
grid.setItems("Foo 1", "Foo 2");
grid.addColumn(item -> item);
- grid.setSelectionModel(new MultiSelectionModelImpl<>(grid));
+ MultiSelectionModelImpl<String> model = new MultiSelectionModelImpl<>(
+ grid);
+ grid.setSelectionModel(model);
addComponent(grid);
addComponent(new Button("Select rows",
@@ -36,5 +42,15 @@ public class GridMultiSelectionOnInit extends AbstractTestUI {
if (request.getParameter("initialSelection") != null) {
grid.getSelectionModel().select("Foo 2");
}
+
+ RadioButtonGroup<SelectAllCheckBoxVisible> rbg = new RadioButtonGroup<>(
+ "Select All Visible",
+ Arrays.asList(SelectAllCheckBoxVisible.VISIBLE,
+ SelectAllCheckBoxVisible.HIDDEN,
+ SelectAllCheckBoxVisible.DEFAULT));
+ rbg.setValue(model.getSelectAllCheckBoxVisible());
+ rbg.addValueChangeListener(
+ event -> model.setSelectAllCheckBoxVisible(event.getValue()));
+ addComponent(rbg);
}
}
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 a39ff27e88..c2628598c5 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
@@ -8,8 +8,8 @@ import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.Optional;
+import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Stream;
@@ -30,6 +30,7 @@ import com.vaadin.ui.Grid.Column;
import com.vaadin.ui.Grid.DetailsGenerator;
import com.vaadin.ui.Grid.FooterRow;
import com.vaadin.ui.Grid.HeaderRow;
+import com.vaadin.ui.Grid.MultiSelectionModel;
import com.vaadin.ui.Label;
import com.vaadin.ui.MenuBar;
import com.vaadin.ui.MenuBar.Command;
@@ -40,6 +41,7 @@ import com.vaadin.ui.StyleGenerator;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.components.grid.MultiSelectionModelImpl;
+import com.vaadin.ui.components.grid.MultiSelectionModelImpl.SelectAllCheckBoxVisible;
import com.vaadin.ui.components.grid.SingleSelectionModelImpl;
import com.vaadin.ui.renderers.DateRenderer;
import com.vaadin.ui.renderers.HtmlRenderer;
@@ -237,14 +239,14 @@ public class GridBasics extends AbstractTestUIWithLog {
}
private void onMultiSelect(MultiSelectionEvent<DataObject> event) {
- Optional<DataObject> firstAdded = event.getNewSelection().stream()
+ Optional<DataObject> firstAdded = event.getAddedSelection().stream()
.findFirst();
- Optional<DataObject> firstRemoved = event.getOldSelection().stream()
+ Optional<DataObject> firstRemoved = event.getRemovedSelection().stream()
.findFirst();
- String addedRow = firstAdded.isPresent() ? firstAdded.toString()
- : "none";
- String removedRow = firstRemoved.isPresent() ? firstRemoved.toString()
+ String addedRow = firstAdded.isPresent() ? firstAdded.get().toString()
: "none";
+ String removedRow = firstRemoved.isPresent()
+ ? firstRemoved.get().toString() : "none";
log("SelectionEvent: Added " + addedRow + ", Removed " + removedRow);
}
@@ -491,12 +493,48 @@ public class GridBasics extends AbstractTestUIWithLog {
.addSelectionListener(this::onSingleSelect);
});
selectionModelItem.addItem("multi", menuItem -> {
- selectionListenerRegistration.remove();
- grid.setSelectionModel(new MultiSelectionModelImpl<>(grid));
- selectionListenerRegistration = ((MultiSelectionModelImpl<DataObject>) grid
- .getSelectionModel())
- .addSelectionListener(this::onMultiSelect);
+ switchToMultiSelect();
+ });
+
+ selectionModelItem.addItem("Select All", menuItem -> {
+ switchToMultiSelect();
+ ((MultiSelectionModel<DataObject>) grid.getSelectionModel())
+ .selectAll();
+ });
+ selectionModelItem.addItem("Deselect All", menuItem -> {
+ switchToMultiSelect();
+ ((MultiSelectionModel<DataObject>) grid.getSelectionModel())
+ .deselectAll();
});
+ selectionModelItem.addItem("SelectAllCheckbox: Visible", menuItem -> {
+ switchToMultiSelect();
+ ((MultiSelectionModelImpl<DataObject>) grid.getSelectionModel())
+ .setSelectAllCheckBoxVisible(
+ SelectAllCheckBoxVisible.VISIBLE);
+ });
+ selectionModelItem.addItem("SelectAllCheckbox: Hidden", menuItem -> {
+ switchToMultiSelect();
+ ((MultiSelectionModelImpl<DataObject>) grid.getSelectionModel())
+ .setSelectAllCheckBoxVisible(
+ SelectAllCheckBoxVisible.HIDDEN);
+ });
+ selectionModelItem.addItem("SelectAllCheckbox: Default", menuItem -> {
+ switchToMultiSelect();
+ ((MultiSelectionModelImpl<DataObject>) grid.getSelectionModel())
+ .setSelectAllCheckBoxVisible(
+ SelectAllCheckBoxVisible.DEFAULT);
+ });
+ }
+
+ private void switchToMultiSelect() {
+ if (!(grid.getSelectionModel() instanceof MultiSelectionModel)) {
+ selectionListenerRegistration.remove();
+ MultiSelectionModelImpl<DataObject> model = new MultiSelectionModelImpl<>(
+ grid);
+ grid.setSelectionModel(model);
+ selectionListenerRegistration = model
+ .addSelectionListener(this::onMultiSelect);
+ }
}
private void createHeaderMenu(MenuItem headerMenu) {
@@ -547,7 +585,8 @@ public class GridBasics extends AbstractTestUIWithLog {
headerRow.join(toMerge).setText(jointCellText);
}
- private void mergeFooterŠ”ells(int rowIndex, String jointCellText, int... columnIndexes) {
+ private void mergeFooterŠ”ells(int rowIndex, String jointCellText,
+ int... columnIndexes) {
FooterRow footerRow = grid.getFooterRow(rowIndex);
List<Column<DataObject, ?>> columns = grid.getColumns();
Set<Grid.FooterCell> toMerge = new HashSet<>();
diff --git a/uitest/src/test/java/com/vaadin/tests/components/grid/GridDisabledMultiselectTest.java b/uitest/src/test/java/com/vaadin/tests/components/grid/GridDisabledMultiselectTest.java
index 8bc58450c8..8ddf7cb1ff 100644
--- a/uitest/src/test/java/com/vaadin/tests/components/grid/GridDisabledMultiselectTest.java
+++ b/uitest/src/test/java/com/vaadin/tests/components/grid/GridDisabledMultiselectTest.java
@@ -48,22 +48,20 @@ public class GridDisabledMultiselectTest extends MultiBrowserTest {
setMultiselect();
- // TODO enable once select all is added back
- // assertThat(getSelectAllCheckBox().isEnabled(), is(false));
+ assertThat(getSelectAllCheckBox().isEnabled(), is(false));
assertThat(getFirstSelectCheckBox().isEnabled(), is(false));
}
@Test
public void checkBoxesAreDisabledAfterDisabled() {
setMultiselect();
- // TODO enable once select all is added back
- // assertThat(getSelectAllCheckBox().isEnabled(), is(true));
+
+ assertThat(getSelectAllCheckBox().isEnabled(), is(true));
assertThat(getFirstSelectCheckBox().isEnabled(), is(true));
disable();
- // TODO enable once select all is added back
- // assertThat(getSelectAllCheckBox().isEnabled(), is(false));
+ assertThat(getSelectAllCheckBox().isEnabled(), is(false));
assertThat(getFirstSelectCheckBox().isEnabled(), is(false));
}
diff --git a/uitest/src/test/java/com/vaadin/tests/components/grid/GridMultiSelectionOnInitTest.java b/uitest/src/test/java/com/vaadin/tests/components/grid/GridMultiSelectionOnInitTest.java
index 6abcb71e8c..09be45414b 100644
--- a/uitest/src/test/java/com/vaadin/tests/components/grid/GridMultiSelectionOnInitTest.java
+++ b/uitest/src/test/java/com/vaadin/tests/components/grid/GridMultiSelectionOnInitTest.java
@@ -35,8 +35,7 @@ import com.vaadin.tests.tb3.MultiBrowserTest;
@TestCategory("grid")
public class GridMultiSelectionOnInitTest extends MultiBrowserTest {
- // TODO enable when select all is added back
- // @Test
+ @Test
public void testSelectAllCheckBoxExists() {
openTestURL();
assertTrue("The select all checkbox was missing.",
@@ -44,9 +43,10 @@ public class GridMultiSelectionOnInitTest extends MultiBrowserTest {
.isElementPresent(By.tagName("input")));
}
- // TODO enable when select all is added back
- // @Test
+ @Test
public void selectAllCellCanBeClicked() throws IOException {
+ openTestURL();
+
GridElement.GridCellElement selectAllCell = $(GridElement.class).first()
.getHeaderCell(0, 0);
diff --git a/uitest/src/test/java/com/vaadin/tests/components/grid/GridSelectAllTest.java b/uitest/src/test/java/com/vaadin/tests/components/grid/GridSelectAllTest.java
index 26fdeedd7b..f58e0db6b4 100644
--- a/uitest/src/test/java/com/vaadin/tests/components/grid/GridSelectAllTest.java
+++ b/uitest/src/test/java/com/vaadin/tests/components/grid/GridSelectAllTest.java
@@ -1,5 +1,6 @@
package com.vaadin.tests.components.grid;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -12,18 +13,7 @@ import com.vaadin.tests.components.grid.basics.GridBasicsTest;
public class GridSelectAllTest extends GridBasicsTest {
- // TODO remove once select all is added
@Test
- public void testSelectAllCheckBoxNotVisble() {
- setSelectionModelMulti();
- GridCellElement header = getGridElement().getHeaderCell(0, 0);
-
- assertFalse("Checkbox visible",
- header.isElementPresent(By.tagName("input")));
- }
-
- // TODO enable once select all is added
- // @Test
public void testSelectAllCheckbox() {
setSelectionModelMulti();
GridCellElement header = getGridElement().getHeaderCell(0, 0);
@@ -41,8 +31,7 @@ public class GridSelectAllTest extends GridBasicsTest {
getGridElement().getRow(100).isSelected());
}
- // TODO enable once select all is added
- // @Test
+ @Test
public void testSelectAllAndSort() {
setSelectionModelMulti();
GridCellElement header = getGridElement().getHeaderCell(0, 0);
@@ -60,13 +49,12 @@ public class GridSelectAllTest extends GridBasicsTest {
"Exception occured, java.lang.IllegalStateException: No item id for key 101 found."));
}
- // TODO enable once select all is added
- // @Test
+ @Test
public void testSelectAllCheckboxWhenChangingModels() {
GridCellElement header;
header = getGridElement().getHeaderCell(0, 0);
assertFalse(
- "Check box shouldn't have been in header for None Selection Model",
+ "Check box shouldn't have been in header for Single Selection Model",
header.isElementPresent(By.tagName("input")));
setSelectionModelMulti();
@@ -93,16 +81,189 @@ public class GridSelectAllTest extends GridBasicsTest {
header.isElementPresent(By.tagName("input")));
}
- // TODO enable once select all is added
- // @Test
+ @Test
public void testSelectAllCheckboxWithHeaderOperations() {
setSelectionModelMulti();
- selectMenuPath("Component", "Header", "Prepend row");
- selectMenuPath("Component", "Header", "Append row");
+ selectMenuPath("Component", "Header", "Prepend header row");
+ assertEquals(2, getGridElement().getHeaderCount());
+ selectMenuPath("Component", "Header", "Append header row");
+ assertEquals(3, getGridElement().getHeaderCount());
GridCellElement header = getGridElement().getHeaderCell(1, 0);
assertTrue("Multi Selection Model should have select all checkbox",
header.isElementPresent(By.tagName("input")));
}
+ @Test
+ public void testSelectAllCheckboxAfterPrependHeaderOperations() {
+ selectMenuPath("Component", "Header", "Prepend header row");
+ assertEquals(2, getGridElement().getHeaderCount());
+
+ setSelectionModelMulti();
+ GridCellElement header = getGridElement().getHeaderCell(1, 0);
+ assertTrue("Multi Selection Model should have select all checkbox",
+ header.isElementPresent(By.tagName("input")));
+
+ setSelectionModelSingle();
+ header = getGridElement().getHeaderCell(1, 0);
+ assertFalse(
+ "Check box shouldn't have been in header for Single Selection Model",
+ header.isElementPresent(By.tagName("input")));
+
+ selectMenuPath("Component", "Header", "Append header row");
+ assertEquals(3, getGridElement().getHeaderCount());
+
+ setSelectionModelMulti();
+ header = getGridElement().getHeaderCell(1, 0);
+ assertTrue("Multi Selection Model should have select all checkbox",
+ header.isElementPresent(By.tagName("input")));
+ }
+
+ @Test
+ public void testSelectAllCheckbox_selectedAllFromClient_afterDeselectingOnClientSide_notSelected() {
+ setSelectionModelMulti();
+
+ verifyAllSelected(false);
+
+ getSelectAllCheckbox().click();
+
+ verifyAllSelected(true);
+
+ getGridElement().getCell(5, 0).click();
+
+ verifyAllSelected(false);
+
+ getGridElement().getCell(5, 0).click();
+
+ verifyAllSelected(false); // EXPECTED since multiselection model can't
+ // verify that all have been selected
+ }
+
+ @Test
+ public void testSelectAllCheckbox_selectedAllFromClient_afterDeselectingOnServerSide_notSelected() {
+ setSelectionModelMulti();
+
+ verifyAllSelected(false);
+
+ getSelectAllCheckbox().click();
+
+ verifyAllSelected(true);
+
+ toggleFirstRowSelection();
+
+ verifyAllSelected(false);
+
+ toggleFirstRowSelection();
+
+ verifyAllSelected(false); // EXPECTED since multiselection model can't
+ // verify that all have been selected
+ }
+
+ @Test
+ public void testSelectAllCheckbox_selectedAllFromServer_afterDeselectingOnClientSide_notSelected() {
+ selectAll(); // triggers selection model change
+
+ verifyAllSelected(true);
+
+ getGridElement().getCell(5, 0).click();
+
+ verifyAllSelected(false);
+
+ getGridElement().getCell(5, 0).click();
+
+ verifyAllSelected(false); // EXPECTED since multiselection model can't
+ // verify that all have been selected
+ }
+
+ @Test
+ public void testSelectAllCheckbox_selectedAllFromServer_afterDeselectingOnServerSide_notSelected() {
+ selectAll(); // triggers selection model change
+
+ verifyAllSelected(true);
+
+ toggleFirstRowSelection();
+
+ verifyAllSelected(false);
+
+ toggleFirstRowSelection();
+
+ verifyAllSelected(false); // EXPECTED since multiselection model can't
+ // verify that all have been selected
+ }
+
+ @Test
+ public void testSelectAllCheckbox_triggerVisibility() {
+ verifySelectAllNotVisible();
+
+ setSelectionModelMulti();
+
+ verifySelectAllVisible();
+
+ setSelectAllCheckBoxHidden();
+
+ verifySelectAllNotVisible();
+
+ setSelectAllCheckBoxDefault();
+
+ verifySelectAllVisible(); // visible because in memory data provider
+
+ setSelectAllCheckBoxHidden();
+
+ verifySelectAllNotVisible();
+
+ setSelectAllCheckBoxVisible();
+
+ verifySelectAllVisible();
+ }
+
+ @Test
+ public void testSelectAllCheckboxNotVisible_selectAllFromServer_staysHidden() {
+ setSelectionModelMulti();
+
+ verifySelectAllVisible();
+
+ setSelectAllCheckBoxHidden();
+
+ verifySelectAllNotVisible();
+
+ selectAll();
+
+ verifySelectAllNotVisible();
+ }
+
+ @Test
+ public void testSelectAll_immediatelyWhenSettingSelectionModel() {
+ verifySelectAllNotVisible();
+
+ selectAll(); // changes selection model too
+
+ verifyAllSelected(true);
+ }
+
+ @Test
+ public void testSelectAllCheckBoxHidden_immediatelyWhenChaningModel() {
+ verifySelectAllNotVisible();
+
+ setSelectAllCheckBoxHidden(); // changes selection model
+
+ verifySelectAllNotVisible();
+ }
+
+ private void verifyAllSelected(boolean selected) {
+ verifySelectAllVisible();
+ assertEquals("Select all checkbox selection state wrong", selected,
+ getSelectAllCheckbox().isSelected());
+ }
+
+ private void verifySelectAllVisible() {
+ assertTrue("Select all checkbox should be displayed",
+ getSelectAllCheckbox().isDisplayed());
+ }
+
+ private void verifySelectAllNotVisible() {
+ assertEquals("Select all checkbox should not be displayed", 0,
+ getGridElement().getHeaderCell(0, 0)
+ .findElements(By.tagName("input")).size());
+ }
+
}
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 f7bd514e7b..e42fcf2d69 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
@@ -127,9 +127,8 @@ public class GridSelectionTest extends GridBasicsTest {
"SingleSelectionEvent: Selected: DataObject[0]"));
}
- // TODO enable once select with space key is added
- // @Test
- public void testKeyboardSelection() {
+ @Test
+ public void testKeyboardWithMultiSelection() {
openTestURL();
setSelectionModelMulti();
@@ -153,8 +152,7 @@ public class GridSelectionTest extends GridBasicsTest {
grid.getRow(3).isSelected());
}
- // TODO enable once select with space key is added
- // @Test
+ @Test
public void testKeyboardWithSingleSelection() {
openTestURL();
setSelectionModelSingle();
@@ -189,7 +187,7 @@ public class GridSelectionTest extends GridBasicsTest {
setSelectionModelMulti();
- getGridElement().getCell(5, 1).click();
+ getGridElement().getCell(5, 0).click();
assertTrue("Row should be selected after clicking",
getRow(5).isSelected());
@@ -210,40 +208,36 @@ public class GridSelectionTest extends GridBasicsTest {
.getAttribute("class")
.contains("v-grid-selection-checkbox"));
- // TODO enable once select all is added
- // GridCellElement header = getGridElement().getHeaderCell(0, 0);
- // assertTrue("Select all CheckBox should have the proper style name
- // set",
- // header.findElement(By.tagName("span")).getAttribute("class")
- // .contains("v-grid-select-all-checkbox"));
+ GridCellElement header = getGridElement().getHeaderCell(0, 0);
+ assertTrue("Select all CheckBox should have the proper style name set",
+ header.findElement(By.tagName("span")).getAttribute("class")
+ .contains("v-grid-select-all-checkbox"));
}
- // TODO enable once select all is added
- // @Test
+ @Test
public void testServerSideSelectTogglesSelectAllCheckBox() {
openTestURL();
setSelectionModelMulti();
- GridCellElement header = getGridElement().getHeaderCell(0, 0);
-
- WebElement selectAll = header.findElement(By.tagName("input"));
+ assertFalse("Select all CheckBox should not be selected",
+ getSelectAllCheckbox().isSelected());
- selectMenuPath("Component", "State", "Select all");
- waitUntilCheckBoxValue(selectAll, true);
+ selectAll();
+ waitUntilCheckBoxValue(getSelectAllCheckbox(), true);
assertTrue("Select all CheckBox wasn't selected as expected",
- selectAll.isSelected());
+ getSelectAllCheckbox().isSelected());
- selectMenuPath("Component", "State", "Select none");
- waitUntilCheckBoxValue(selectAll, false);
+ deselectAll();
+ waitUntilCheckBoxValue(getSelectAllCheckbox(), false);
assertFalse("Select all CheckBox was selected unexpectedly",
- selectAll.isSelected());
+ getSelectAllCheckbox().isSelected());
- selectMenuPath("Component", "State", "Select all");
- waitUntilCheckBoxValue(selectAll, true);
+ selectAll();
+ waitUntilCheckBoxValue(getSelectAllCheckbox(), true);
getGridElement().getCell(5, 0).click();
- waitUntilCheckBoxValue(selectAll, false);
+ waitUntilCheckBoxValue(getSelectAllCheckbox(), false);
assertFalse("Select all CheckBox was selected unexpectedly",
- selectAll.isSelected());
+ getSelectAllCheckbox().isSelected());
}
@Test
@@ -272,10 +266,6 @@ public class GridSelectionTest extends GridBasicsTest {
}, 5);
}
- private void toggleFirstRowSelection() {
- selectMenuPath("Component", "Body rows", "Toggle first row selection");
- }
-
private GridRowElement getRow(int i) {
return getGridElement().getRow(i);
}
diff --git a/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridBasicSelectionTest.java b/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridBasicSelectionTest.java
deleted file mode 100644
index 82de23a90b..0000000000
--- a/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridBasicSelectionTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.vaadin.tests.components.grid.basics;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-import org.openqa.selenium.Keys;
-import org.openqa.selenium.interactions.Actions;
-
-import com.vaadin.testbench.customelements.GridElement;
-import com.vaadin.testbench.elements.GridElement.GridRowElement;
-
-public class GridBasicSelectionTest extends GridBasicsTest {
-
- @Test
- public void testKeyboardWithSingleSelection() {
-
- GridElement grid = getGridElement();
- grid.getCell(3, 1).click();
-
- assertTrue("Grid row 3 was not selected with clicking.",
- grid.getRow(3).isSelected());
-
- new Actions(getDriver()).sendKeys(Keys.SPACE).perform();
-
- assertTrue("Grid row 3 was not deselected with space key.",
- !grid.getRow(3).isSelected());
-
- new Actions(getDriver()).sendKeys(Keys.SPACE).perform();
-
- assertTrue("Grid row 3 was not selected with space key.",
- grid.getRow(3).isSelected());
-
- grid.scrollToRow(500);
-
- new Actions(getDriver()).sendKeys(Keys.SPACE).perform();
-
- assertTrue("Grid row 3 was not deselected with space key.",
- !grid.getRow(3).isSelected());
- }
-
- @Test
- public void testSingleSelectionUpdatesFromServer() {
- GridElement grid = getGridElement();
- assertFalse("First row was selected from start",
- grid.getRow(0).isSelected());
- toggleFirstRowSelection();
- assertTrue("First row was not selected.", getRow(0).isSelected());
- assertTrue("Selection event was not correct", logContainsText(
- "SingleSelectionEvent: Selected: DataObject[0]"));
- grid.getCell(5, 0).click();
- assertTrue("Fifth row was not selected.", getRow(5).isSelected());
- assertFalse("First row was still selected.", getRow(0).isSelected());
- assertTrue("Selection event was not correct", logContainsText(
- "SingleSelectionEvent: Selected: DataObject[5]"));
- grid.getCell(0, 3).click();
- assertTrue("Selection event was not correct", logContainsText(
- "SingleSelectionEvent: Selected: DataObject[0]"));
- toggleFirstRowSelection();
- assertTrue("Selection event was not correct",
- logContainsText("SingleSelectionEvent: Selected: none"));
- assertFalse("First row was still selected.", getRow(0).isSelected());
- assertFalse("Fifth row was still selected.", getRow(5).isSelected());
-
- grid.scrollToRow(600);
- grid.getCell(595, 3).click();
- assertTrue("Row 595 was not selected.", getRow(595).isSelected());
- assertTrue("Selection event was not correct", logContainsText(
- "SingleSelectionEvent: Selected: DataObject[595]"));
- toggleFirstRowSelection();
- assertFalse("Row 595 was still selected.", getRow(595).isSelected());
- assertTrue("First row was not selected.", getRow(0).isSelected());
- assertTrue("Selection event was not correct", logContainsText(
- "SingleSelectionEvent: Selected: DataObject[0]"));
- }
-
- private void toggleFirstRowSelection() {
- selectMenuPath("Component", "Body rows", "Toggle first row selection");
- }
-
- private GridRowElement getRow(int i) {
- return getGridElement().getRow(i);
- }
-}
diff --git a/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridBasicsTest.java b/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridBasicsTest.java
index ff6789f600..20e94cb7a6 100644
--- a/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridBasicsTest.java
+++ b/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridBasicsTest.java
@@ -215,6 +215,18 @@ public abstract class GridBasicsTest extends MultiBrowserTest {
getGridVerticalScrollbar())).intValue();
}
+ protected void toggleFirstRowSelection() {
+ selectMenuPath("Component", "Body rows", "Toggle first row selection");
+ }
+
+ protected void selectAll() {
+ selectMenuPath("Component", "State", "Selection model", "Select All");
+ }
+
+ protected void deselectAll() {
+ selectMenuPath("Component", "State", "Selection model", "Deselect All");
+ }
+
protected void setSelectionModelMulti() {
selectMenuPath("Component", "State", "Selection model", "multi");
}
@@ -223,7 +235,28 @@ public abstract class GridBasicsTest extends MultiBrowserTest {
selectMenuPath("Component", "State", "Selection model", "single");
}
- // TODO enable once select all is added
+ protected void setSelectAllCheckBoxVisible() {
+ selectMenuPath("Component", "State", "Selection model",
+ "SelectAllCheckbox: Visible");
+ }
+
+ protected void setSelectAllCheckBoxHidden() {
+ selectMenuPath("Component", "State", "Selection model",
+ "SelectAllCheckbox: Hidden");
+ }
+
+ protected void setSelectAllCheckBoxDefault() {
+ selectMenuPath("Component", "State", "Selection model",
+ "SelectAllCheckbox: Default");
+ }
+
+ protected WebElement getSelectAllCheckbox() {
+ GridCellElement header = getGridElement().getHeaderCell(0, 0);
+
+ return header.findElement(By.tagName("input"));
+ }
+
+ // TODO enable once select model none is added
// protected void setSelectionModelNone() {
// selectMenuPath("Component", "State", "Selection model", "none");
// }