com.vaadin.ui.components.grid.GridDragSource Maven / Gradle / Ivy
/*
* 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.ui.components.grid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.vaadin.data.provider.DataGenerator;
import com.vaadin.server.SerializableFunction;
import com.vaadin.shared.Registration;
import com.vaadin.shared.ui.dnd.DragSourceState;
import com.vaadin.shared.ui.dnd.DropEffect;
import com.vaadin.shared.ui.grid.GridDragSourceRpc;
import com.vaadin.shared.ui.grid.GridDragSourceState;
import com.vaadin.ui.Grid;
import com.vaadin.ui.dnd.DragSourceExtension;
import elemental.json.Json;
import elemental.json.JsonObject;
/**
* Makes a Grid's rows draggable for HTML5 drag and drop functionality.
*
* When dragging a selected row, all the visible selected rows are dragged. Note
* that ONLY visible rows are taken into account.
*
* @param
* The Grid bean type.
* @author Vaadin Ltd.
* @since 8.1
* @see GridRowDragger
*/
public class GridDragSource extends DragSourceExtension> {
/**
* Drag data generator that appends drag data to each row.
*/
private DataGenerator dragDataGenerator;
/**
* Collection of drag data generator functions. Functions are executed for
* each row and results are stored under their corresponding key.
*/
private final Map> generatorFunctions;
/**
* Default drag data generator for Grid. It creates a list of row values
* separated by a tabulator character ({@code \t}).
*
*
* "column1_value\tcolumn2_value\t ... columnN_value"
*
*/
private final SerializableFunction defaultGridGenerator = item -> {
StringBuilder generatedValue = new StringBuilder();
getParent().getColumns().forEach(column -> {
generatedValue.append("\t"); // Tab separated values
generatedValue.append(column.getValueProvider().apply(item));
});
return generatedValue.substring(1);
};
/**
* Extends a Grid and makes it's rows draggable.
*
* @param target
* Grid to be extended.
*/
public GridDragSource(Grid target) {
super(target);
// Create drag data generator
dragDataGenerator = new DataGenerator() {
/**
* Drag data generator. Appends drag data to row data json if generator
* function(s) are set by the user of this extension.
*
* @param item
* Row item for data generation.
* @param jsonObject
* Row data in json format.
*/
@Override
public void generateData(Object item, JsonObject jsonObject) {
JsonObject generatedValues = Json.createObject();
generatorFunctions.forEach((type, generator) -> generatedValues
.put(type, generator.apply((T) item)));
jsonObject.put(GridDragSourceState.JSONKEY_DRAG_DATA, generatedValues);
}
};
// Add drag data generator to Grid
target.getDataCommunicator().addDataGenerator(dragDataGenerator);
generatorFunctions = new HashMap<>();
// Set default generator function for "text" parameter
generatorFunctions.put(DragSourceState.DATA_TYPE_TEXT,
defaultGridGenerator);
}
/**
* Gets the grid this extension has been attached to.
*
* @return the grid for this extension
* @since 8.2
*/
public Grid getGrid() {
return getParent();
}
@Override
protected void registerDragSourceRpc() {
registerRpc(new GridDragSourceRpc() {
@Override
public void dragStart(List draggedItemKeys) {
GridDragStartEvent event = new GridDragStartEvent<>(
getParent(), getState(false).effectAllowed,
getDraggedItems(getParent(), draggedItemKeys));
fireEvent(event);
}
@Override
public void dragEnd(DropEffect dropEffect,
List draggedItemKeys) {
GridDragEndEvent event = new GridDragEndEvent<>(getParent(),
dropEffect,
getDraggedItems(getParent(), draggedItemKeys));
fireEvent(event);
}
});
}
/**
* Collects the dragged items of a Grid given the list of item keys.
*/
private List getDraggedItems(Grid grid,
List draggedItemKeys) {
if (draggedItemKeys == null || draggedItemKeys.isEmpty()) {
throw new IllegalStateException(
"The drag event does not contain dragged items");
}
return draggedItemKeys.stream()
.map(key -> grid.getDataCommunicator().getKeyMapper().get(key))
.collect(Collectors.toList());
}
/**
* Sets a generator function for customizing drag data. The generated value
* will be accessible using the same {@code type} as the generator is set
* here. The function is executed for each item in the Grid during data
* generation. Return a {@link String} to be appended to the row as {@code
* type} data.
*
* Example, building a JSON object that contains the item's values:
*
*
* dragSourceExtension.setDragDataGenerator("application/json", item ->
* {
* StringBuilder builder = new StringBuilder();
* builder.append("{");
* getParent().getColumns().forEach(column -> {
* builder.append("\"" + column.getCaption() + "\"");
* builder.append(":");
* builder.append("\"" + column.getValueProvider().apply(item) + "\"");
* builder.append(",");
* });
* builder.setLength(builder.length() - 1); // Remove last comma
* builder.append("}");
* return builder.toString();
* }
*
*
* @param type
* Type of the generated data. The generated value will be
* accessible during drop using this type.
* @param generator
* Function to be executed on row data generation.
*/
public void setDragDataGenerator(String type,
SerializableFunction generator) {
generatorFunctions.put(type, generator);
}
/**
* Remove the generator function set for the given type.
*
* @param type
* Type of the generator to be removed.
*/
public void clearDragDataGenerator(String type) {
generatorFunctions.remove(type);
}
/**
* Returns the drag data generator function for the given type.
*
* @param type
* Type of the generated data.
* @return Drag data generator function for the given type.
*/
public SerializableFunction getDragDataGenerator(String type) {
return generatorFunctions.get(type);
}
/**
* Attaches dragstart listener for the current drag source grid.
*
* @param listener
* Listener to handle the dragstart event.
* @return Handle to be used to remove this listener.
* @see GridDragStartEvent
*/
public Registration addGridDragStartListener(
GridDragStartListener listener) {
return addListener(DragSourceState.EVENT_DRAGSTART,
GridDragStartEvent.class, listener,
GridDragStartListener.DRAG_START_METHOD);
}
/**
* Attaches dragend listener for the current drag source grid.
*
* @param listener
* Listener to handle the dragend event.
* @return Handle to be used to remove this listener.
* @see GridDragEndEvent
*/
public Registration addGridDragEndListener(
GridDragEndListener listener) {
return addListener(DragSourceState.EVENT_DRAGEND,
GridDragEndEvent.class, listener,
GridDragEndListener.DRAG_END_METHOD);
}
@Override
public void remove() {
getParent().getDataCommunicator()
.removeDataGenerator(dragDataGenerator);
super.remove();
}
@Override
protected GridDragSourceState getState() {
return (GridDragSourceState) super.getState();
}
@Override
protected GridDragSourceState getState(boolean markAsDirty) {
return (GridDragSourceState) super.getState(markAsDirty);
}
}