From f2d8f812efa067b4baa7e27c0ea76f7596b291e6 Mon Sep 17 00:00:00 2001 From: Pekka Hyvönen Date: Fri, 11 Nov 2016 09:41:43 +0200 Subject: Add MultiSelect support for Grid Still missing following things coming in next patches: - select all checkbox - firing an event when data provider is changed in grid - read only selection models for grid Part 1 for vaadin/framework8-issues#232 Change-Id: Ib2c7c81a838f43cb7c521a56d50139c91961f54a --- .../grid/MultiSelectionModelConnector.java | 101 +++++++++++++++++++++ .../grid/SingleSelectionModelConnector.java | 15 ++- .../com/vaadin/client/data/SelectionModel.java | 92 ------------------- .../client/widget/grid/events/SelectAllEvent.java | 2 +- .../widget/grid/selection/SelectionEvent.java | 9 -- .../widget/grid/selection/SelectionModel.java | 80 ++++++++++++++++ .../main/java/com/vaadin/client/widgets/Grid.java | 82 +++++------------ 7 files changed, 213 insertions(+), 168 deletions(-) create mode 100644 client/src/main/java/com/vaadin/client/connectors/grid/MultiSelectionModelConnector.java delete mode 100644 client/src/main/java/com/vaadin/client/data/SelectionModel.java create mode 100644 client/src/main/java/com/vaadin/client/widget/grid/selection/SelectionModel.java (limited to 'client/src') 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 new file mode 100644 index 0000000000..7b421be15b --- /dev/null +++ b/client/src/main/java/com/vaadin/client/connectors/grid/MultiSelectionModelConnector.java @@ -0,0 +1,101 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.connectors.grid; + +import com.vaadin.client.ServerConnector; +import com.vaadin.client.extensions.AbstractExtensionConnector; +import com.vaadin.client.renderers.Renderer; +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.shared.data.DataCommunicatorConstants; +import com.vaadin.shared.data.selection.GridMultiSelectServerRpc; +import com.vaadin.shared.ui.Connect; + +import elemental.json.JsonObject; + +/** + * Connector for server side multiselection model implementation. + * + * @author Vaadin Ltd + * + * @since 8.0 + * + */ +@Connect(com.vaadin.ui.components.grid.MultiSelectionModelImpl.class) +public class MultiSelectionModelConnector extends AbstractExtensionConnector { + + /** + * Client side multiselection model implementation. + */ + protected class MultiSelectionModel implements SelectionModel, + SelectionModelWithSelectionColumn { + + @Override + public Renderer getRenderer() { + // this method is only called once when the selection model is set + // to grid + return new MultiSelectionRenderer<>(getGrid()); + } + + @Override + public void select(JsonObject item) { + getRpcProxy(GridMultiSelectServerRpc.class) + .select(item.getString(DataCommunicatorConstants.KEY)); + } + + @Override + public void deselect(JsonObject item) { + // handled by diffstate + 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."); + } + + @Override + public boolean isSelected(JsonObject item) { + return SelectionModel.isItemSelected(item); + } + + } + + @Override + protected void extend(ServerConnector target) { + getGrid().setSelectionModel(new MultiSelectionModel()); + } + + @Override + public GridConnector getParent() { + return (GridConnector) super.getParent(); + } + + /** + * Shorthand for fetching the grid this selection model is bound to. + * + * @return the grid + */ + protected Grid getGrid() { + return getParent().getWidget(); + } + +} 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 0a30dfa070..33a6d9d9b6 100644 --- a/client/src/main/java/com/vaadin/client/connectors/grid/SingleSelectionModelConnector.java +++ b/client/src/main/java/com/vaadin/client/connectors/grid/SingleSelectionModelConnector.java @@ -15,11 +15,9 @@ */ package com.vaadin.client.connectors.grid; -import java.util.Set; - import com.vaadin.client.ServerConnector; -import com.vaadin.client.data.SelectionModel; import com.vaadin.client.extensions.AbstractExtensionConnector; +import com.vaadin.client.widget.grid.selection.SelectionModel; import com.vaadin.shared.data.DataCommunicatorConstants; import com.vaadin.shared.data.selection.SelectionServerRpc; import com.vaadin.shared.ui.Connect; @@ -33,7 +31,7 @@ import elemental.json.JsonObject; * * @since 8.0 */ -@Connect(com.vaadin.ui.components.grid.SingleSelectionModel.class) +@Connect(com.vaadin.ui.components.grid.SingleSelectionModelImpl.class) public class SingleSelectionModelConnector extends AbstractExtensionConnector { @Override @@ -54,14 +52,13 @@ public class SingleSelectionModelConnector extends AbstractExtensionConnector { } @Override - public Set getSelectedItems() { - throw new UnsupportedOperationException( - "Selected item not known on the client side"); + public boolean isSelected(JsonObject item) { + return SelectionModel.isItemSelected(item); } @Override - public boolean isSelected(JsonObject item) { - return SelectionModel.isItemSelected(item); + public void deselectAll() { + getRpcProxy(SelectionServerRpc.class).select(null); } }); diff --git a/client/src/main/java/com/vaadin/client/data/SelectionModel.java b/client/src/main/java/com/vaadin/client/data/SelectionModel.java deleted file mode 100644 index 4079140128..0000000000 --- a/client/src/main/java/com/vaadin/client/data/SelectionModel.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2000-2016 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.client.data; - -import java.util.Set; - -import com.vaadin.shared.data.DataCommunicatorConstants; - -import elemental.json.JsonObject; - -/** - * Models the selection logic of a {@code Grid} component. Determines how items - * can be selected and deselected. - * - * @author Vaadin Ltd. - * - * @param - * the type of the items to select - * @since 8.0 - */ -public interface SelectionModel { - - /** - * Selects the given item. If another item was already selected, that item - * is deselected. - * - * @param item - * the item to select, not null - */ - void select(T item); - - /** - * Deselects the given item. If the item is not currently selected, does - * nothing. - * - * @param item - * the item to deselect, not null - */ - void deselect(T item); - - /** - * Returns a set of the currently selected items. It is safe to invoke other - * {@code SelectionModel} methods while iterating over the set. - * - * @return the items in the current selection, not null - */ - Set getSelectedItems(); - - /** - * Returns whether the given item is currently selected. - * - * @param item - * the item to check, not null - * @return {@code true} if the item is selected, {@code false} otherwise - */ - boolean isSelected(T item); - - /** - * Deselects all currently selected items. - */ - default void deselectAll() { - getSelectedItems().forEach(this::deselect); - } - - /** - * Gets the selected state from a given grid row json object. This is a - * helper method for grid selection models. - * - * @param item - * a json object - * @return {@code true} if the json object is marked as selected; - * {@code false} if not - */ - public static boolean isItemSelected(JsonObject item) { - return item.hasKey(DataCommunicatorConstants.SELECTED) - && item.getBoolean(DataCommunicatorConstants.SELECTED); - } - -} 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 2ac2f51e4b..25ce090d6e 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 @@ -16,7 +16,7 @@ package com.vaadin.client.widget.grid.events; import com.google.gwt.event.shared.GwtEvent; -import com.vaadin.client.data.SelectionModel; +import com.vaadin.client.widget.grid.selection.SelectionModel; /** * A select all event, fired by the Grid when it needs all rows in data source diff --git a/client/src/main/java/com/vaadin/client/widget/grid/selection/SelectionEvent.java b/client/src/main/java/com/vaadin/client/widget/grid/selection/SelectionEvent.java index 8219b8998c..707330ad34 100644 --- a/client/src/main/java/com/vaadin/client/widget/grid/selection/SelectionEvent.java +++ b/client/src/main/java/com/vaadin/client/widget/grid/selection/SelectionEvent.java @@ -136,15 +136,6 @@ public class SelectionEvent extends GwtEvent { return Collections.unmodifiableCollection(removed); } - /** - * Gets currently selected rows. - * - * @return a non-null collection containing all currently selected rows. - */ - public Collection getSelected() { - return grid.getSelectedRows(); - } - /** * Gets a type identifier for this event. * diff --git a/client/src/main/java/com/vaadin/client/widget/grid/selection/SelectionModel.java b/client/src/main/java/com/vaadin/client/widget/grid/selection/SelectionModel.java new file mode 100644 index 0000000000..27e099ad46 --- /dev/null +++ b/client/src/main/java/com/vaadin/client/widget/grid/selection/SelectionModel.java @@ -0,0 +1,80 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.widget.grid.selection; + +import com.vaadin.shared.data.DataCommunicatorConstants; + +import elemental.json.JsonObject; + +/** + * Models the selection logic of a {@code Grid} component. Determines how items + * can be selected and deselected. + * + * @author Vaadin Ltd. + * + * @param + * the type of the items to select + * @since 8.0 + */ +public interface SelectionModel { + + /** + * Selects the given item. If another item was already selected, that item + * is deselected. + * + * @param item + * the item to select, not null + */ + void select(T item); + + /** + * Deselects the given item. If the item is not currently selected, does + * nothing. + * + * @param item + * the item to deselect, not null + */ + void deselect(T item); + + /** + * Returns whether the given item is currently selected. + * + * @param item + * the item to check, not null + * @return {@code true} if the item is selected, {@code false} otherwise + */ + boolean isSelected(T item); + + /** + * Deselects all currently selected items. + */ + void deselectAll(); + + /** + * Gets the selected state from a given grid row json object. This is a + * helper method for grid selection models. + * + * @param item + * a json object + * @return {@code true} if the json object is marked as selected; + * {@code false} if not + */ + public static boolean isItemSelected(JsonObject item) { + return item.hasKey(DataCommunicatorConstants.SELECTED) + && item.getBoolean(DataCommunicatorConstants.SELECTED); + } + +} 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 0cad901ec2..97775aa482 100644 --- a/client/src/main/java/com/vaadin/client/widgets/Grid.java +++ b/client/src/main/java/com/vaadin/client/widgets/Grid.java @@ -83,7 +83,6 @@ import com.vaadin.client.WidgetUtil; import com.vaadin.client.data.DataChangeHandler; import com.vaadin.client.data.DataSource; import com.vaadin.client.data.DataSource.RowHandle; -import com.vaadin.client.data.SelectionModel; import com.vaadin.client.renderers.ComplexRenderer; import com.vaadin.client.renderers.Renderer; import com.vaadin.client.renderers.WidgetRenderer; @@ -160,6 +159,7 @@ import com.vaadin.client.widget.grid.selection.HasSelectionHandlers; import com.vaadin.client.widget.grid.selection.MultiSelectionRenderer; import com.vaadin.client.widget.grid.selection.SelectionEvent; import com.vaadin.client.widget.grid.selection.SelectionHandler; +import com.vaadin.client.widget.grid.selection.SelectionModel; import com.vaadin.client.widget.grid.selection.SelectionModelWithSelectionColumn; import com.vaadin.client.widget.grid.sort.Sort; import com.vaadin.client.widget.grid.sort.SortEvent; @@ -2483,8 +2483,8 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, setStyleName(rowWithFocusStyle, rowFocusStyleName, true); } } else if (rowWithFocusStyle == row.getElement() - || (containerWithFocus != escalator.getBody() - && rowWithFocusStyle != null)) { + || containerWithFocus != escalator.getBody() + && rowWithFocusStyle != null) { // Remove focus style. setStyleName(rowWithFocusStyle, rowFocusStyleName, false); rowWithFocusStyle = null; @@ -2781,9 +2781,9 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, * a range of added rows */ public void rowsAddedToBody(Range added) { - boolean bodyHasFocus = (containerWithFocus == escalator.getBody()); - boolean insertionIsAboveFocusedCell = (added - .getStart() <= rowWithFocus); + boolean bodyHasFocus = containerWithFocus == escalator.getBody(); + boolean insertionIsAboveFocusedCell = added + .getStart() <= rowWithFocus; if (bodyHasFocus && insertionIsAboveFocusedCell) { rowWithFocus += added.length(); rowWithFocus = Math.min(rowWithFocus, @@ -2853,17 +2853,11 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, @Override protected void setDefaultHeaderContent(HeaderCell selectionCell) { - /* - * TODO: Currently the select all check box is shown when multi - * selection is in use. This might result in malfunctions if no - * SelectAllHandlers are present. - * - * Later on this could be fixed so that it check such handlers - * exist. - */ final SelectionModel model = getSelectionModel(); + final boolean shouldSelectAllCheckBoxBeShown = getHandlerCount( + SelectAllEvent.getType()) > 0; - if (selectAllCheckBox == null) { + if (selectAllCheckBox == null && shouldSelectAllCheckBoxBeShown) { selectAllCheckBox = GWT.create(CheckBox.class); selectAllCheckBox.setStylePrimaryName( getStylePrimaryName() + SELECT_ALL_CHECKBOX_CLASSNAME); @@ -2919,7 +2913,8 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, } } }); - } else { + } else if (selectAllCheckBox != null + && !shouldSelectAllCheckBoxBeShown) { for (HeaderRow row : header.getRows()) { if (row.getCell(this) .getType() == GridStaticCellType.WIDGET) { @@ -3300,8 +3295,8 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, setColumnSizes(columnSizes); for (Column column : nonFixedColumns) { - final int expandRatio = (defaultExpandRatios ? 1 - : column.getExpandRatio()); + final int expandRatio = defaultExpandRatios ? 1 + : column.getExpandRatio(); final double maxWidth = getMaxWidth(column); final double newWidth = Math.min(maxWidth, column.getWidthActual()); @@ -3433,8 +3428,8 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, boolean hasAutoWidth = column.getWidth() < 0; if (hasAutoWidth && currentWidth < minWidth) { columnSizes.put(columnIndex, minWidth); - pixelsToRemoveFromOtherColumns += (minWidth - - currentWidth); + pixelsToRemoveFromOtherColumns += minWidth + - currentWidth; minWidthsCausedReflows = true; /* @@ -3853,7 +3848,7 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, .getFirstChildElement(); double height = WidgetUtil .getRequiredHeightBoundingClientRectDouble(firstHeaderCell) - - (WidgetUtil.measureVerticalBorder(getElement()) / 2); + - WidgetUtil.measureVerticalBorder(getElement()) / 2; openCloseButton.setHeight(height + "px"); } @@ -3929,7 +3924,7 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, toggle.setStyleName("hidden", column.isHidden()); } else if (columnToHidingToggleMap.containsKey(column)) { sidebar.menuBar - .removeItem((columnToHidingToggleMap.remove(column))); + .removeItem(columnToHidingToggleMap.remove(column)); } updateTogglesOrder(); } @@ -4333,8 +4328,7 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, final int colspan = header.getRow(eventCell.getRowIndex()) .getCell(eventCell.getColumn()).getColspan(); if (latestColumnDropIndex != draggedColumnIndex - && latestColumnDropIndex != (draggedColumnIndex - + colspan)) { + && latestColumnDropIndex != draggedColumnIndex + colspan) { List> columns = getColumns(); List> reordered = new ArrayList<>(); if (draggedColumnIndex < latestColumnDropIndex) { @@ -4523,7 +4517,7 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, } } - if (leftBound == (rightBound - 1)) { + if (leftBound == rightBound - 1) { return; } @@ -5404,7 +5398,7 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, setStyleName(rowElement, rowHasDataStyleName, hasData); } - boolean isEvenIndex = (row.getRow() % 2 == 0); + boolean isEvenIndex = row.getRow() % 2 == 0; setStyleName(rowElement, rowStripeStyleName, !isEvenIndex); rowReference.set(rowIndex, rowData, rowElement); @@ -5869,11 +5863,6 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, setSelectionModel(new SelectionModel() { - @Override - public Set getSelectedItems() { - return Collections.emptySet(); - } - @Override public void select(T item) { } @@ -5887,6 +5876,10 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, return false; } + @Override + public void deselectAll() { + } + }); escalator.getBody().setSpacerUpdater(gridSpacerUpdater); @@ -7657,32 +7650,6 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, getSelectionModel().deselectAll(); } - /** - * Gets last selected row from the current SelectionModel. - *

- * Only selection models implementing {@link SelectionModel.Single} are - * valid for this method; for anything else, use the - * {@link Grid#getSelectedRows()} method. - * - * @return a selected row reference, or null, if no row is selected - * @throws IllegalStateException - * if the current selection model is not an instance of - * {@link SelectionModel.Single} - */ - public T getSelectedRow() { - return getSelectionModel().getSelectedItems().stream().findFirst() - .orElse(null); - } - - /** - * Gets currently selected rows from the current selection model. - * - * @return a non-null collection containing all currently selected rows. - */ - public Collection getSelectedRows() { - return getSelectionModel().getSelectedItems(); - } - @Override public HandlerRegistration addSelectionHandler( final SelectionHandler handler) { @@ -8877,4 +8844,5 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, } return null; } + } -- cgit v1.2.3