diff options
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"); // } |