com.vaadin.client.connectors.MultiSelectionModelConnector Maven / Gradle / Ivy
Show all versions of vaadin-client Show documentation
/*
* Copyright 2000-2014 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.Grid.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> {
private Multi selectionModel = createSelectionModel();
private SpaceSelectHandler spaceHandler;
@Override
protected void extend(ServerConnector target) {
getGrid().setSelectionModel(selectionModel);
spaceHandler = new SpaceSelectHandler(getGrid());
}
@Override
public void onUnregister() {
spaceHandler.removeHandler();
}
@Override
protected Multi 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 {
private ComplexRenderer renderer = null;
private Set> selected = new HashSet>();
private Set> deselected = new HashSet>();
private HandlerRegistration selectAll;
private HandlerRegistration dataAvailable;
private Range availableRows;
private boolean batchSelect = false;
@Override
public void setGrid(Grid grid) {
super.setGrid(grid);
if (grid != null) {
renderer = createSelectionColumnRenderer(grid);
selectAll = getGrid().addSelectAllHandler(
new SelectAllHandler() {
@Override
public void onSelectAll(
SelectAllEvent 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 createSelectionColumnRenderer(
Grid grid) {
return new MultiSelectionRenderer(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 dataSource = getGrid().getDataSource();
for (int i = availableRows.getStart(); i < availableRows.getEnd(); ++i) {
final JsonObject row = dataSource.getRow(i);
if (row != null) {
RowHandle handle = dataSource.getHandle(row);
markAsSelected(handle, true);
}
}
getRpcProxy(MultiSelectionModelServerRpc.class).selectAll();
}
@Override
public Renderer 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 dataSource = getGrid().getDataSource();
for (int i = availableRows.getStart(); i < availableRows.getEnd(); ++i) {
final JsonObject row = dataSource.getRow(i);
if (row != null) {
RowHandle 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 rows) {
if (rows.isEmpty()) {
return false;
}
for (JsonObject row : rows) {
RowHandle 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.
*
* 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 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 rows) {
if (rows.isEmpty()) {
return false;
}
for (JsonObject row : rows) {
RowHandle 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 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 row : selected) {
row.unpin();
}
}
selected.clear();
}
private List getRowKeys(Set> handles) {
List keys = new ArrayList();
for (RowHandle handle : handles) {
keys.add(getRowKey(handle.getRow()));
}
return keys;
}
private Set getRows(Set> handles) {
Set rows = new HashSet();
for (RowHandle 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 getSelectedRowsBatch() {
return Collections.unmodifiableSet(getRows(selected));
}
@Override
public Collection getDeselectedRowsBatch() {
return Collections.unmodifiableSet(getRows(deselected));
}
}
}