123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386 |
- /*
- * 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;
-
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.HashSet;
- import java.util.List;
- import java.util.Set;
-
- import com.google.gwt.event.shared.HandlerRegistration;
- import com.google.gwt.user.client.ui.CheckBox;
- 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.renderers.ComplexRenderer;
- import com.vaadin.client.renderers.Renderer;
- import com.vaadin.client.widget.grid.DataAvailableEvent;
- import com.vaadin.client.widget.grid.DataAvailableHandler;
- import com.vaadin.client.widget.grid.events.SelectAllEvent;
- import com.vaadin.client.widget.grid.events.SelectAllHandler;
- import com.vaadin.client.widget.grid.selection.MultiSelectionRenderer;
- import com.vaadin.client.widget.grid.selection.SelectionModel;
- import com.vaadin.client.widget.grid.selection.SelectionModel.Multi;
- import com.vaadin.client.widget.grid.selection.SpaceSelectHandler;
- import com.vaadin.client.widgets.Grid;
- import com.vaadin.client.widgets.Grid.HeaderCell;
- import com.vaadin.shared.ui.Connect;
- import com.vaadin.shared.ui.grid.GridState;
- import com.vaadin.shared.ui.grid.Range;
- import com.vaadin.shared.ui.grid.selection.MultiSelectionModelServerRpc;
- import com.vaadin.shared.ui.grid.selection.MultiSelectionModelState;
- import com.vaadin.ui.LegacyGrid.MultiSelectionModel;
-
- import elemental.json.JsonObject;
-
- /**
- * Connector for server-side {@link MultiSelectionModel}.
- *
- * @since 7.6
- * @author Vaadin Ltd
- */
- @Connect(MultiSelectionModel.class)
- public class MultiSelectionModelConnector extends
- AbstractSelectionModelConnector<SelectionModel.Multi<JsonObject>> {
-
- private Multi<JsonObject> selectionModel = createSelectionModel();
- private SpaceSelectHandler<JsonObject> spaceHandler;
-
- @Override
- protected void extend(ServerConnector target) {
- getGrid().setSelectionModel(selectionModel);
- spaceHandler = new SpaceSelectHandler<JsonObject>(getGrid());
- }
-
- @Override
- public void onUnregister() {
- spaceHandler.removeHandler();
- }
-
- @Override
- protected Multi<JsonObject> createSelectionModel() {
- return new MultiSelectionModel();
- }
-
- @Override
- public MultiSelectionModelState getState() {
- return (MultiSelectionModelState) super.getState();
- }
-
- @OnStateChange("allSelected")
- void updateSelectAllCheckbox() {
- if (selectionModel.getSelectionColumnRenderer() != null) {
- HeaderCell cell = getGrid().getDefaultHeaderRow()
- .getCell(getGrid().getColumn(0));
- CheckBox widget = (CheckBox) cell.getWidget();
- widget.setValue(getState().allSelected, false);
- }
- }
-
- protected class MultiSelectionModel extends AbstractSelectionModel
- implements SelectionModel.Multi.Batched<JsonObject> {
-
- private ComplexRenderer<Boolean> renderer = null;
- private Set<RowHandle<JsonObject>> selected = new HashSet<RowHandle<JsonObject>>();
- private Set<RowHandle<JsonObject>> deselected = new HashSet<RowHandle<JsonObject>>();
- private HandlerRegistration selectAll;
- private HandlerRegistration dataAvailable;
- private Range availableRows;
- private boolean batchSelect = false;
-
- @Override
- public void setGrid(Grid<JsonObject> grid) {
- super.setGrid(grid);
- if (grid != null) {
- renderer = createSelectionColumnRenderer(grid);
- selectAll = getGrid().addSelectAllHandler(
- new SelectAllHandler<JsonObject>() {
-
- @Override
- public void onSelectAll(
- SelectAllEvent<JsonObject> event) {
- selectAll();
- }
- });
- dataAvailable = getGrid()
- .addDataAvailableHandler(new DataAvailableHandler() {
-
- @Override
- public void onDataAvailable(
- DataAvailableEvent event) {
- availableRows = event.getAvailableRows();
- }
- });
- } else if (renderer != null) {
- selectAll.removeHandler();
- dataAvailable.removeHandler();
- renderer = null;
- }
- }
-
- /**
- * Creates a selection column renderer. This method can be overridden to
- * use a custom renderer or use {@code null} to disable the selection
- * column.
- *
- * @param grid
- * the grid for this selection model
- * @return selection column renderer or {@code null} if not needed
- */
- protected ComplexRenderer<Boolean> createSelectionColumnRenderer(
- Grid<JsonObject> grid) {
- return new MultiSelectionRenderer<JsonObject>(grid);
- }
-
- /**
- * Selects all available rows, sends request to server to select
- * everything.
- */
- public void selectAll() {
- assert !isBeingBatchSelected() : "Can't select all in middle of a batch selection.";
-
- 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);
- markAsSelected(handle, true);
- }
- }
-
- getRpcProxy(MultiSelectionModelServerRpc.class).selectAll();
- }
-
- @Override
- public Renderer<Boolean> getSelectionColumnRenderer() {
- return renderer;
- }
-
- /**
- * {@inheritDoc}
- *
- * @return {@code false} if rows is empty, else {@code true}
- */
- @Override
- public boolean select(JsonObject... rows) {
- return select(Arrays.asList(rows));
- }
-
- /**
- * {@inheritDoc}
- *
- * @return {@code false} if rows is empty, else {@code true}
- */
- @Override
- public boolean deselect(JsonObject... rows) {
- return deselect(Arrays.asList(rows));
- }
-
- /**
- * {@inheritDoc}
- *
- * @return always {@code true}
- */
- @Override
- public boolean deselectAll() {
- assert !isBeingBatchSelected() : "Can't select all in middle of a batch selection.";
-
- 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);
- markAsSelected(handle, false);
- }
- }
-
- getRpcProxy(MultiSelectionModelServerRpc.class).deselectAll();
-
- return true;
- }
-
- /**
- * {@inheritDoc}
- *
- * @return {@code false} if rows is empty, else {@code true}
- */
- @Override
- public boolean select(Collection<JsonObject> rows) {
- if (rows.isEmpty()) {
- return false;
- }
-
- for (JsonObject row : rows) {
- RowHandle<JsonObject> rowHandle = getRowHandle(row);
- if (markAsSelected(rowHandle, true)) {
- selected.add(rowHandle);
- }
- }
-
- if (!isBeingBatchSelected()) {
- sendSelected();
- }
- return true;
- }
-
- /**
- * 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
- * @return {@code true} if selected status changed; {@code false} if not
- */
- protected boolean markAsSelected(RowHandle<JsonObject> row,
- boolean selected) {
- if (selected && !isSelected(row.getRow())) {
- row.getRow().put(GridState.JSONKEY_SELECTED, true);
- } else if (!selected && isSelected(row.getRow())) {
- row.getRow().remove(GridState.JSONKEY_SELECTED);
- } else {
- return false;
- }
-
- row.updateRow();
-
- if (isBeingBatchSelected()) {
- row.pin();
- }
- return true;
- }
-
- /**
- * {@inheritDoc}
- *
- * @return {@code false} if rows is empty, else {@code true}
- */
- @Override
- public boolean deselect(Collection<JsonObject> rows) {
- if (rows.isEmpty()) {
- return false;
- }
-
- for (JsonObject row : rows) {
- RowHandle<JsonObject> rowHandle = getRowHandle(row);
- if (markAsSelected(rowHandle, false)) {
- deselected.add(rowHandle);
- }
- }
-
- if (!isBeingBatchSelected()) {
- sendDeselected();
- }
- return true;
- }
-
- /**
- * Sends a deselect RPC call to server-side containing all deselected
- * rows. Unpins any pinned rows.
- */
- private void sendDeselected() {
- getRpcProxy(MultiSelectionModelServerRpc.class)
- .deselect(getRowKeys(deselected));
-
- if (isBeingBatchSelected()) {
- for (RowHandle<JsonObject> row : deselected) {
- row.unpin();
- }
- }
-
- deselected.clear();
- }
-
- /**
- * Sends a select RPC call to server-side containing all selected rows.
- * Unpins any pinned rows.
- */
- private void sendSelected() {
- getRpcProxy(MultiSelectionModelServerRpc.class)
- .select(getRowKeys(selected));
-
- if (isBeingBatchSelected()) {
- for (RowHandle<JsonObject> row : selected) {
- row.unpin();
- }
- }
-
- selected.clear();
- }
-
- private List<String> getRowKeys(Set<RowHandle<JsonObject>> handles) {
- List<String> keys = new ArrayList<String>();
- for (RowHandle<JsonObject> handle : handles) {
- keys.add(getRowKey(handle.getRow()));
- }
- return keys;
- }
-
- private Set<JsonObject> getRows(Set<RowHandle<JsonObject>> handles) {
- Set<JsonObject> rows = new HashSet<JsonObject>();
- for (RowHandle<JsonObject> handle : handles) {
- rows.add(handle.getRow());
- }
- return rows;
- }
-
- @Override
- public void startBatchSelect() {
- assert selected.isEmpty()
- && deselected.isEmpty() : "Row caches were not clear.";
- batchSelect = true;
- }
-
- @Override
- public void commitBatchSelect() {
- assert batchSelect : "Not batch selecting.";
- if (!selected.isEmpty()) {
- sendSelected();
- }
-
- if (!deselected.isEmpty()) {
- sendDeselected();
- }
- batchSelect = false;
- }
-
- @Override
- public boolean isBeingBatchSelected() {
- return batchSelect;
- }
-
- @Override
- public Collection<JsonObject> getSelectedRowsBatch() {
- return Collections.unmodifiableSet(getRows(selected));
- }
-
- @Override
- public Collection<JsonObject> getDeselectedRowsBatch() {
- return Collections.unmodifiableSet(getRows(deselected));
- }
- }
- }
|