2 * Copyright 2000-2016 Vaadin Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
16 package com.vaadin.v7.client.connectors;
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.HashSet;
23 import java.util.List;
26 import com.google.gwt.event.shared.HandlerRegistration;
27 import com.google.gwt.user.client.ui.CheckBox;
28 import com.vaadin.client.ServerConnector;
29 import com.vaadin.client.annotations.OnStateChange;
30 import com.vaadin.client.data.DataSource;
31 import com.vaadin.client.data.DataSource.RowHandle;
32 import com.vaadin.shared.ui.Connect;
33 import com.vaadin.shared.ui.grid.Range;
34 import com.vaadin.v7.client.renderers.ComplexRenderer;
35 import com.vaadin.v7.client.renderers.Renderer;
36 import com.vaadin.v7.client.widget.grid.DataAvailableEvent;
37 import com.vaadin.v7.client.widget.grid.DataAvailableHandler;
38 import com.vaadin.v7.client.widget.grid.events.SelectAllEvent;
39 import com.vaadin.v7.client.widget.grid.events.SelectAllHandler;
40 import com.vaadin.v7.client.widget.grid.selection.MultiSelectionRenderer;
41 import com.vaadin.v7.client.widget.grid.selection.SelectionModel;
42 import com.vaadin.v7.client.widget.grid.selection.SelectionModel.Multi;
43 import com.vaadin.v7.client.widget.grid.selection.SpaceSelectHandler;
44 import com.vaadin.v7.client.widgets.Grid;
45 import com.vaadin.v7.client.widgets.Grid.HeaderCell;
46 import com.vaadin.v7.shared.ui.grid.GridState;
47 import com.vaadin.v7.shared.ui.grid.selection.MultiSelectionModelServerRpc;
48 import com.vaadin.v7.shared.ui.grid.selection.MultiSelectionModelState;
49 import com.vaadin.v7.ui.Grid.MultiSelectionModel;
51 import elemental.json.JsonObject;
54 * Connector for server-side {@link MultiSelectionModel}.
59 @Connect(MultiSelectionModel.class)
60 public class MultiSelectionModelConnector extends
61 AbstractSelectionModelConnector<SelectionModel.Multi<JsonObject>> {
63 private Multi<JsonObject> selectionModel = createSelectionModel();
64 private SpaceSelectHandler<JsonObject> spaceHandler;
67 protected void extend(ServerConnector target) {
68 getGrid().setSelectionModel(selectionModel);
69 spaceHandler = new SpaceSelectHandler<JsonObject>(getGrid());
73 public void onUnregister() {
74 spaceHandler.removeHandler();
78 protected Multi<JsonObject> createSelectionModel() {
79 return new MultiSelectionModel();
83 public MultiSelectionModelState getState() {
84 return (MultiSelectionModelState) super.getState();
87 @OnStateChange("allSelected")
88 void updateSelectAllCheckbox() {
89 if (selectionModel.getSelectionColumnRenderer() != null) {
90 HeaderCell cell = getGrid().getDefaultHeaderRow()
91 .getCell(getGrid().getColumn(0));
92 CheckBox widget = (CheckBox) cell.getWidget();
93 widget.setValue(getState().allSelected, false);
97 protected class MultiSelectionModel extends AbstractSelectionModel
98 implements SelectionModel.Multi.Batched<JsonObject> {
100 private ComplexRenderer<Boolean> renderer = null;
101 private Set<RowHandle<JsonObject>> selected = new HashSet<RowHandle<JsonObject>>();
102 private Set<RowHandle<JsonObject>> deselected = new HashSet<RowHandle<JsonObject>>();
103 private HandlerRegistration selectAll;
104 private HandlerRegistration dataAvailable;
105 private Range availableRows;
106 private boolean batchSelect = false;
109 public void setGrid(Grid<JsonObject> grid) {
112 renderer = createSelectionColumnRenderer(grid);
113 selectAll = getGrid().addSelectAllHandler(
114 new SelectAllHandler<JsonObject>() {
117 public void onSelectAll(
118 SelectAllEvent<JsonObject> event) {
122 dataAvailable = getGrid()
123 .addDataAvailableHandler(new DataAvailableHandler() {
126 public void onDataAvailable(
127 DataAvailableEvent event) {
128 availableRows = event.getAvailableRows();
131 } else if (renderer != null) {
132 selectAll.removeHandler();
133 dataAvailable.removeHandler();
139 * Creates a selection column renderer. This method can be overridden to
140 * use a custom renderer or use {@code null} to disable the selection
144 * the grid for this selection model
145 * @return selection column renderer or {@code null} if not needed
147 protected ComplexRenderer<Boolean> createSelectionColumnRenderer(
148 Grid<JsonObject> grid) {
149 return new MultiSelectionRenderer<JsonObject>(grid);
153 * Selects all available rows, sends request to server to select
156 public void selectAll() {
157 assert !isBeingBatchSelected() : "Can't select all in middle of a batch selection.";
159 DataSource<JsonObject> dataSource = getGrid().getDataSource();
160 for (int i = availableRows.getStart(); i < availableRows
162 final JsonObject row = dataSource.getRow(i);
164 RowHandle<JsonObject> handle = dataSource.getHandle(row);
165 markAsSelected(handle, true);
169 getRpcProxy(MultiSelectionModelServerRpc.class).selectAll();
173 public Renderer<Boolean> getSelectionColumnRenderer() {
180 * @return {@code false} if rows is empty, else {@code true}
183 public boolean select(JsonObject... rows) {
184 return select(Arrays.asList(rows));
190 * @return {@code false} if rows is empty, else {@code true}
193 public boolean deselect(JsonObject... rows) {
194 return deselect(Arrays.asList(rows));
200 * @return always {@code true}
203 public boolean deselectAll() {
204 assert !isBeingBatchSelected() : "Can't select all in middle of a batch selection.";
206 DataSource<JsonObject> dataSource = getGrid().getDataSource();
207 for (int i = availableRows.getStart(); i < availableRows
209 final JsonObject row = dataSource.getRow(i);
211 RowHandle<JsonObject> handle = dataSource.getHandle(row);
212 markAsSelected(handle, false);
216 getRpcProxy(MultiSelectionModelServerRpc.class).deselectAll();
224 * @return {@code false} if rows is empty, else {@code true}
227 public boolean select(Collection<JsonObject> rows) {
228 if (rows.isEmpty()) {
232 for (JsonObject row : rows) {
233 RowHandle<JsonObject> rowHandle = getRowHandle(row);
234 if (markAsSelected(rowHandle, true)) {
235 selected.add(rowHandle);
239 if (!isBeingBatchSelected()) {
246 * Marks the given row to be selected or deselected. Returns true if the
247 * value actually changed.
249 * Note: If selection model is in batch select state, the row will be
255 * {@code true} if row should be selected; {@code false} if
257 * @return {@code true} if selected status changed; {@code false} if not
259 protected boolean markAsSelected(RowHandle<JsonObject> row,
261 if (selected && !isSelected(row.getRow())) {
262 row.getRow().put(GridState.JSONKEY_SELECTED, true);
263 } else if (!selected && isSelected(row.getRow())) {
264 row.getRow().remove(GridState.JSONKEY_SELECTED);
271 if (isBeingBatchSelected()) {
280 * @return {@code false} if rows is empty, else {@code true}
283 public boolean deselect(Collection<JsonObject> rows) {
284 if (rows.isEmpty()) {
288 for (JsonObject row : rows) {
289 RowHandle<JsonObject> rowHandle = getRowHandle(row);
290 if (markAsSelected(rowHandle, false)) {
291 deselected.add(rowHandle);
295 if (!isBeingBatchSelected()) {
302 * Sends a deselect RPC call to server-side containing all deselected
303 * rows. Unpins any pinned rows.
305 private void sendDeselected() {
306 getRpcProxy(MultiSelectionModelServerRpc.class)
307 .deselect(getRowKeys(deselected));
309 if (isBeingBatchSelected()) {
310 for (RowHandle<JsonObject> row : deselected) {
319 * Sends a select RPC call to server-side containing all selected rows.
320 * Unpins any pinned rows.
322 private void sendSelected() {
323 getRpcProxy(MultiSelectionModelServerRpc.class)
324 .select(getRowKeys(selected));
326 if (isBeingBatchSelected()) {
327 for (RowHandle<JsonObject> row : selected) {
335 private List<String> getRowKeys(Set<RowHandle<JsonObject>> handles) {
336 List<String> keys = new ArrayList<String>();
337 for (RowHandle<JsonObject> handle : handles) {
338 keys.add(getRowKey(handle.getRow()));
343 private Set<JsonObject> getRows(Set<RowHandle<JsonObject>> handles) {
344 Set<JsonObject> rows = new HashSet<JsonObject>();
345 for (RowHandle<JsonObject> handle : handles) {
346 rows.add(handle.getRow());
352 public void startBatchSelect() {
353 assert selected.isEmpty()
354 && deselected.isEmpty() : "Row caches were not clear.";
359 public void commitBatchSelect() {
360 assert batchSelect : "Not batch selecting.";
361 if (!selected.isEmpty()) {
365 if (!deselected.isEmpty()) {
372 public boolean isBeingBatchSelected() {
377 public Collection<JsonObject> getSelectedRowsBatch() {
378 return Collections.unmodifiableSet(getRows(selected));
382 public Collection<JsonObject> getDeselectedRowsBatch() {
383 return Collections.unmodifiableSet(getRows(deselected));