summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/src/main/java/com/vaadin/client/connectors/grid/GridDragSourceExtensionConnector.java119
-rw-r--r--client/src/main/java/com/vaadin/client/extensions/DragSourceExtensionConnector.java61
-rw-r--r--client/src/main/java/com/vaadin/client/widget/escalator/RowContainer.java14
-rw-r--r--client/src/main/java/com/vaadin/client/widgets/Escalator.java18
-rw-r--r--server/src/main/java/com/vaadin/ui/GridDragSourceExtension.java125
-rw-r--r--shared/src/main/java/com/vaadin/shared/ui/grid/GridDragSourceExtensionState.java38
-rw-r--r--uitest/src/main/java/com/vaadin/tests/components/grid/GridDragAndDrop.java103
7 files changed, 466 insertions, 12 deletions
diff --git a/client/src/main/java/com/vaadin/client/connectors/grid/GridDragSourceExtensionConnector.java b/client/src/main/java/com/vaadin/client/connectors/grid/GridDragSourceExtensionConnector.java
new file mode 100644
index 0000000000..f402f2396d
--- /dev/null
+++ b/client/src/main/java/com/vaadin/client/connectors/grid/GridDragSourceExtensionConnector.java
@@ -0,0 +1,119 @@
+/*
+ * 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.grid;
+
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.dom.client.TableRowElement;
+import com.vaadin.client.ServerConnector;
+import com.vaadin.client.extensions.DragSourceExtensionConnector;
+import com.vaadin.client.widget.escalator.RowContainer;
+import com.vaadin.client.widgets.Escalator;
+import com.vaadin.shared.Range;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.grid.GridDragSourceExtensionState;
+import com.vaadin.ui.GridDragSourceExtension;
+
+import elemental.events.Event;
+import elemental.json.JsonObject;
+
+/**
+ * Adds HTML5 drag and drop functionality to a {@link com.vaadin.client.widgets.Grid
+ * Grid}'s rows. This is the client side counterpart of {@link
+ * GridDragSourceExtension}.
+ *
+ * @author Vaadin Ltd
+ * @since
+ */
+@Connect(GridDragSourceExtension.class)
+public class GridDragSourceExtensionConnector extends
+ DragSourceExtensionConnector {
+
+ private GridConnector gridConnector;
+
+ @Override
+ protected void extend(ServerConnector target) {
+ this.gridConnector = (GridConnector) target;
+
+ // Set newly added rows draggable
+ getGridBody().setNewEscalatorRowCallback(
+ rows -> rows.forEach(this::setDraggable));
+
+ // Add drag listeners to body element
+ addDragListeners(getGridBody().getElement());
+ }
+
+ @Override
+ protected void onDragStart(Event event) {
+ super.onDragStart(event);
+
+ if (event.getTarget() instanceof TableRowElement) {
+ TableRowElement row = (TableRowElement) event.getTarget();
+ int rowIndex = ((Escalator.AbstractRowContainer) getGridBody())
+ .getLogicalRowIndex(row);
+
+ JsonObject rowData = gridConnector.getDataSource().getRow(rowIndex);
+
+ // Set drag data in DataTransfer object
+ ((NativeEvent) event).getDataTransfer()
+ .setData(GridDragSourceExtensionState.DATA_TYPE_DRAG_DATA,
+ getDragData(rowData).toJson());
+ }
+ }
+
+ /**
+ * Gets drag data from the row data if exists or returns complete row data
+ * otherwise.
+ *
+ * @param row
+ * Row data.
+ * @return Drag data if present or row data otherwise.
+ */
+ private JsonObject getDragData(JsonObject row) {
+ return row.hasKey(GridDragSourceExtensionState.JSONKEY_DRAG_DATA)
+ ? row.getObject(GridDragSourceExtensionState.JSONKEY_DRAG_DATA)
+ : row;
+ }
+
+ @Override
+ public void onUnregister() {
+ super.onUnregister();
+
+ // Remove draggable from all row elements in the escalator
+ Range visibleRange = getEscalator().getVisibleRowRange();
+ for (int i = visibleRange.getStart(); i < visibleRange.getEnd(); i++) {
+ removeDraggable(getGridBody().getRowElement(i));
+ }
+
+ // Remove drag listeners from body element
+ removeDragListeners(getGridBody().getElement());
+
+ // Remove callback for newly added rows
+ getGridBody().setNewEscalatorRowCallback(null);
+ }
+
+ private Escalator getEscalator() {
+ return gridConnector.getWidget().getEscalator();
+ }
+
+ private RowContainer.BodyRowContainer getGridBody() {
+ return getEscalator().getBody();
+ }
+
+ @Override
+ public GridDragSourceExtensionState getState() {
+ return (GridDragSourceExtensionState) super.getState();
+ }
+}
diff --git a/client/src/main/java/com/vaadin/client/extensions/DragSourceExtensionConnector.java b/client/src/main/java/com/vaadin/client/extensions/DragSourceExtensionConnector.java
index 3094042826..23797ce886 100644
--- a/client/src/main/java/com/vaadin/client/extensions/DragSourceExtensionConnector.java
+++ b/client/src/main/java/com/vaadin/client/extensions/DragSourceExtensionConnector.java
@@ -56,29 +56,66 @@ public class DragSourceExtensionConnector extends AbstractExtensionConnector {
protected void extend(ServerConnector target) {
dragSourceWidget = ((ComponentConnector) target).getWidget();
- Element dragSourceElement = getDraggableElement();
+ setDraggable(getDraggableElement());
+ addDragListeners(getDraggableElement());
+ }
+
+ /**
+ * Sets the given element draggable and adds class name.
+ *
+ * @param element
+ * Element to be set draggable.
+ */
+ protected void setDraggable(Element element) {
+ element.setDraggable(Element.DRAGGABLE_TRUE);
+ element.addClassName(CLASS_DRAGGABLE);
+ }
+
+ /**
+ * Removes draggable and class name from the given element.
+ *
+ * @param element
+ * Element to remove draggable from.
+ */
+ protected void removeDraggable(Element element) {
+ element.setDraggable(Element.DRAGGABLE_FALSE);
+ element.removeClassName(CLASS_DRAGGABLE);
+ }
- dragSourceElement.setDraggable(Element.DRAGGABLE_TRUE);
- dragSourceElement.addClassName(CLASS_DRAGGABLE);
+ /**
+ * Adds dragstart and dragend event listeners to the given DOM element.
+ *
+ * @param element
+ * DOM element to attach event listeners to.
+ */
+ protected void addDragListeners(Element element) {
+ EventTarget target = element.cast();
- EventTarget dragSource = dragSourceElement.cast();
+ target.addEventListener(Event.DRAGSTART, dragStartListener);
+ target.addEventListener(Event.DRAGEND, dragEndListener);
+ }
- // dragstart
- dragSource.addEventListener(Event.DRAGSTART, dragStartListener);
+ /**
+ * Removes dragstart and dragend event listeners from the given DOM element.
+ *
+ * @param element
+ * DOM element to remove event listeners from.
+ */
+ protected void removeDragListeners(Element element) {
+ EventTarget target = element.cast();
- // dragend
- dragSource.addEventListener(Event.DRAGEND, dragEndListener);
+ target.removeEventListener(Event.DRAGSTART, dragStartListener);
+ target.removeEventListener(Event.DRAGEND, dragEndListener);
}
@Override
public void onUnregister() {
super.onUnregister();
- EventTarget dragSource = (EventTarget) getDraggableElement();
+ Element dragSource = getDraggableElement();
- // Remove listeners
- dragSource.removeEventListener(Event.DRAGSTART, dragStartListener);
- dragSource.removeEventListener(Event.DRAGEND, dragEndListener);
+ removeDraggable(dragSource);
+ removeDragListeners(dragSource);
}
/**
diff --git a/client/src/main/java/com/vaadin/client/widget/escalator/RowContainer.java b/client/src/main/java/com/vaadin/client/widget/escalator/RowContainer.java
index 0105aa687c..ca00ca9b63 100644
--- a/client/src/main/java/com/vaadin/client/widget/escalator/RowContainer.java
+++ b/client/src/main/java/com/vaadin/client/widget/escalator/RowContainer.java
@@ -16,6 +16,9 @@
package com.vaadin.client.widget.escalator;
+import java.util.List;
+import java.util.function.Consumer;
+
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.TableRowElement;
import com.google.gwt.dom.client.TableSectionElement;
@@ -116,6 +119,17 @@ public interface RowContainer {
@Override
public void removeRows(int index, int numberOfRows)
throws IndexOutOfBoundsException, IllegalArgumentException;
+
+ /**
+ * Sets a callback function that is executed when new rows are added to
+ * the escalator.
+ *
+ * @param consumer
+ * A Consumer function that receives the newly added table row
+ * elements.
+ */
+ public void setNewEscalatorRowCallback(
+ Consumer<List<TableRowElement>> consumer);
}
/**
diff --git a/client/src/main/java/com/vaadin/client/widgets/Escalator.java b/client/src/main/java/com/vaadin/client/widgets/Escalator.java
index 7bb078a94a..1f223c1d85 100644
--- a/client/src/main/java/com/vaadin/client/widgets/Escalator.java
+++ b/client/src/main/java/com/vaadin/client/widgets/Escalator.java
@@ -25,7 +25,9 @@ import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Optional;
import java.util.TreeMap;
+import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -2401,6 +2403,12 @@ public class Escalator extends Widget
@Deprecated
private int topRowLogicalIndex = 0;
+ /**
+ * A callback function to be executed after new rows are added to the
+ * escalator.
+ */
+ private Consumer<List<TableRowElement>> newEscalatorRowCallback;
+
private void setTopRowLogicalIndex(int topRowLogicalIndex) {
if (LogConfiguration.loggingIsEnabled(Level.INFO)) {
Logger.getLogger("Escalator.BodyRowContainer")
@@ -2992,6 +3000,10 @@ public class Escalator extends Widget
y += spacerContainer.getSpacerHeight(i);
}
+ // Execute the registered callback function for newly created rows
+ Optional.ofNullable(newEscalatorRowCallback)
+ .ifPresent(callback -> callback.accept(addedRows));
+
return addedRows;
} else {
return Collections.emptyList();
@@ -3982,6 +3994,12 @@ public class Escalator extends Widget
int padding) {
spacerContainer.scrollToSpacer(spacerIndex, destination, padding);
}
+
+ @Override
+ public void setNewEscalatorRowCallback(
+ Consumer<List<TableRowElement>> callback) {
+ this.newEscalatorRowCallback = callback;
+ }
}
private class ColumnConfigurationImpl implements ColumnConfiguration {
diff --git a/server/src/main/java/com/vaadin/ui/GridDragSourceExtension.java b/server/src/main/java/com/vaadin/ui/GridDragSourceExtension.java
new file mode 100644
index 0000000000..9f7e9ec67d
--- /dev/null
+++ b/server/src/main/java/com/vaadin/ui/GridDragSourceExtension.java
@@ -0,0 +1,125 @@
+/*
+ * 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.ui;
+
+import java.util.Optional;
+
+import com.vaadin.data.provider.DataGenerator;
+import com.vaadin.event.dnd.DragSourceExtension;
+import com.vaadin.server.SerializableFunction;
+import com.vaadin.shared.ui.grid.GridDragSourceExtensionState;
+
+import elemental.json.JsonObject;
+
+/**
+ * Makes a Grid's rows draggable for HTML5 drag and drop functionality.
+ *
+ * @param <T>
+ * The Grid bean type.
+ * @author Vaadin Ltd.
+ * @since
+ */
+public class GridDragSourceExtension<T> extends DragSourceExtension<Grid<T>> {
+
+ /**
+ * Drag data generator that appends drag data to each row.
+ */
+ private DataGenerator<T> dragDataGenerator;
+
+ /**
+ * Drag data generator function that is executed for each row.
+ */
+ private SerializableFunction<T, JsonObject> generatorFunction;
+
+ /**
+ * Extends a Grid and makes it's rows draggable.
+ *
+ * @param target
+ * Grid to be extended.
+ */
+ public GridDragSourceExtension(Grid<T> target) {
+ super(target);
+
+ // Create drag data generator
+ dragDataGenerator = this::generateDragData;
+
+ // Add drag data generator to Grid
+ target.addDataGenerator(dragDataGenerator);
+ }
+
+ /**
+ * Drag data generator. Appends drag data to row data json if generator
+ * function is set by the user of this extension.
+ *
+ * @param item
+ * Row item for data generation.
+ * @param jsonObject
+ * Row data in json format.
+ */
+ private void generateDragData(T item, JsonObject jsonObject) {
+ Optional.ofNullable(generatorFunction).ifPresent(generator -> jsonObject
+ .put(GridDragSourceExtensionState.JSONKEY_DRAG_DATA,
+ generator.apply(item)));
+ }
+
+ /**
+ * Sets a generator function for customizing drag data. The function is
+ * executed for each item in the Grid during data generation. Return a
+ * {@link JsonObject} to be appended to the row data.
+ * <p>
+ * Example:
+ * <pre>
+ * dragSourceExtension.setDragDataGenerator(item -> {
+ * JsonObject dragData = Json.createObject();
+ * dragData.put("someKey", item.getValue());
+ * return dragData;
+ * });
+ * </pre>
+ *
+ * @param generator
+ * Function to be executed on row data generation.
+ */
+ public void setDragDataGenerator(
+ SerializableFunction<T, JsonObject> generator) {
+ generatorFunction = generator;
+ }
+
+ /**
+ * Returns the generator function for customizing drag data.
+ *
+ * @return Drag data generator function.
+ */
+ public SerializableFunction<T, JsonObject> getDragDataGenerator() {
+ return generatorFunction;
+ }
+
+ @Override
+ public void remove() {
+ super.remove();
+
+ getParent().removeDataGenerator(dragDataGenerator);
+ }
+
+ @Override
+ protected GridDragSourceExtensionState getState() {
+ return (GridDragSourceExtensionState) super.getState();
+ }
+
+ @Override
+ protected GridDragSourceExtensionState getState(boolean markAsDirty) {
+ return (GridDragSourceExtensionState) super.getState(markAsDirty);
+ }
+}
diff --git a/shared/src/main/java/com/vaadin/shared/ui/grid/GridDragSourceExtensionState.java b/shared/src/main/java/com/vaadin/shared/ui/grid/GridDragSourceExtensionState.java
new file mode 100644
index 0000000000..39a5917146
--- /dev/null
+++ b/shared/src/main/java/com/vaadin/shared/ui/grid/GridDragSourceExtensionState.java
@@ -0,0 +1,38 @@
+/*
+ * 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.shared.ui.grid;
+
+import com.vaadin.shared.ui.dnd.DragSourceState;
+
+/**
+ * State class containing parameters for GridDragSourceExtension.
+ *
+ * @author Vaadin Ltd
+ * @since
+ */
+public class GridDragSourceExtensionState extends DragSourceState {
+
+ /**
+ * Data type for storing the dragged row's data.
+ */
+ public static final String DATA_TYPE_DRAG_DATA = "grid-drag-data";
+
+ /**
+ * Json key for storing data for a dragged row.
+ */
+ public static final String JSONKEY_DRAG_DATA = "drag-data";
+
+}
diff --git a/uitest/src/main/java/com/vaadin/tests/components/grid/GridDragAndDrop.java b/uitest/src/main/java/com/vaadin/tests/components/grid/GridDragAndDrop.java
new file mode 100644
index 0000000000..32c147f15f
--- /dev/null
+++ b/uitest/src/main/java/com/vaadin/tests/components/grid/GridDragAndDrop.java
@@ -0,0 +1,103 @@
+/*
+ * 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.tests.components.grid;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.IntStream;
+
+import com.vaadin.event.dnd.DropTargetExtension;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.ui.grid.GridDragSourceExtensionState;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.ui.Grid;
+import com.vaadin.ui.GridDragSourceExtension;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Layout;
+
+import elemental.json.Json;
+import elemental.json.JsonObject;
+
+public class GridDragAndDrop extends AbstractTestUIWithLog {
+ @Override
+ protected void setup(VaadinRequest request) {
+ // Drag source
+ Grid<Bean> dragSourceComponent = new Grid<>();
+
+ dragSourceComponent.setItems(createItems(50));
+ dragSourceComponent.addColumn(Bean::getId).setCaption("ID");
+ dragSourceComponent.addColumn(Bean::getValue).setCaption("Value");
+
+ GridDragSourceExtension<Bean> dragSource = new GridDragSourceExtension<>(
+ dragSourceComponent);
+ dragSource.setDragDataGenerator(bean -> {
+ JsonObject ret = Json.createObject();
+ ret.put("val", bean.getValue());
+ return ret;
+ });
+
+ Label dropTargetComponent = new Label("Drop here");
+ DropTargetExtension<Label> dropTarget = new DropTargetExtension<>(
+ dropTargetComponent);
+
+ dropTarget.addDropListener(event -> {
+ log(event.getTransferData(
+ GridDragSourceExtensionState.DATA_TYPE_DRAG_DATA));
+ });
+
+ Layout layout = new HorizontalLayout();
+ layout.addComponents(dragSourceComponent, dropTargetComponent);
+
+ addComponent(layout);
+ }
+
+ private List<Bean> createItems(int num) {
+ List<Bean> items = new ArrayList<>(num);
+
+ IntStream.range(0, num)
+ .forEach(i -> items.add(new Bean("id_" + i, "value_" + i)));
+
+ return items;
+ }
+
+ public static class Bean {
+ private String id;
+ private String value;
+
+ public Bean(String id, String value) {
+ this.id = id;
+ this.value = value;
+ }
+
+ public String getId() {
+
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+ }
+}