com.vaadin.v7.client.connectors.MultiSelectionModelConnector Maven / Gradle / Ivy
Show all versions of vaadin-compatibility-client Show documentation
/*
* Copyright (C) 2000-2024 Vaadin Ltd
*
* This program is available under Vaadin Commercial License and Service Terms.
*
* See for the full
* license.
*/
package com.vaadin.v7.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 java.util.logging.Logger;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.web.bindery.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.shared.Range;
import com.vaadin.shared.ui.Connect;
import com.vaadin.v7.client.renderers.ComplexRenderer;
import com.vaadin.v7.client.renderers.Renderer;
import com.vaadin.v7.client.widget.grid.DataAvailableEvent;
import com.vaadin.v7.client.widget.grid.DataAvailableHandler;
import com.vaadin.v7.client.widget.grid.events.SelectAllEvent;
import com.vaadin.v7.client.widget.grid.events.SelectAllHandler;
import com.vaadin.v7.client.widget.grid.selection.HasUserSelectionAllowed;
import com.vaadin.v7.client.widget.grid.selection.MultiSelectionRenderer;
import com.vaadin.v7.client.widget.grid.selection.SelectionModel;
import com.vaadin.v7.client.widget.grid.selection.SelectionModel.Multi;
import com.vaadin.v7.client.widget.grid.selection.SpaceSelectHandler;
import com.vaadin.v7.client.widgets.Grid;
import com.vaadin.v7.client.widgets.Grid.Column;
import com.vaadin.v7.client.widgets.Grid.HeaderCell;
import com.vaadin.v7.client.widgets.Grid.SelectionColumn;
import com.vaadin.v7.shared.ui.grid.GridState;
import com.vaadin.v7.shared.ui.grid.selection.MultiSelectionModelServerRpc;
import com.vaadin.v7.shared.ui.grid.selection.MultiSelectionModelState;
import com.vaadin.v7.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;
private HandlerRegistration readOnlyStateChangeHandlerRegistration;
@Override
protected void extend(ServerConnector target) {
getGrid().setSelectionModel(selectionModel);
spaceHandler = new SpaceSelectHandler(getGrid());
readOnlyStateChangeHandlerRegistration = target.addStateChangeHandler(
"readOnly", e -> updateUserSelectionAllowed());
}
@Override
public void onUnregister() {
spaceHandler.removeHandler();
readOnlyStateChangeHandlerRegistration.removeHandler();
super.onUnregister();
}
@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);
}
}
@OnStateChange("userSelectionAllowed")
void updateUserSelectionAllowed() {
if (selectionModel instanceof HasUserSelectionAllowed) {
((HasUserSelectionAllowed) selectionModel)
.setUserSelectionAllowed(getState().userSelectionAllowed);
} else {
getLogger().warning("userSelectionAllowed set to "
+ getState().userSelectionAllowed
+ " but the selection model does not implement "
+ HasUserSelectionAllowed.class.getSimpleName());
}
}
private static Logger getLogger() {
return Logger.getLogger(MultiSelectionModelConnector.class.getName());
}
/**
* The default multi selection model used for this connector.
*
*/
protected class MultiSelectionModel extends AbstractSelectionModel
implements SelectionModel.Multi.Batched,
HasUserSelectionAllowed {
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;
private boolean userSelectionAllowed = true;
@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));
}
@Override
public boolean isUserSelectionAllowed() {
return userSelectionAllowed;
}
@Override
public void setUserSelectionAllowed(boolean userSelectionAllowed) {
this.userSelectionAllowed = userSelectionAllowed
&& !getParent().isReadOnly();
for (Column, JsonObject> c : getGrid().getColumns()) {
if (c instanceof SelectionColumn) {
((SelectionColumn) c)
.setUserSelectionAllowed(this.userSelectionAllowed);
}
}
}
}
}