Browse Source

Make Grid rows draggable (#8690)

* Make Grid rows draggable (#8396)

* Add @author and @since tags, javadocs and minor fixes
reviewable/pr8979/r1
Adam Wagner 7 years ago
parent
commit
37039e64cc

+ 104
- 0
client/src/main/java/com/vaadin/client/connectors/grid/GridDragSourceExtensionConnector.java View File

@@ -0,0 +1,104 @@
/*
* 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);

((NativeEvent) event).getDataTransfer()
.setData(GridDragSourceExtensionState.DATA_TYPE_ROW_DATA,
rowData.toJson());
}
}

@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();
}
}

+ 49
- 12
client/src/main/java/com/vaadin/client/extensions/DragSourceExtensionConnector.java View File

@@ -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);
}

/**

+ 14
- 0
client/src/main/java/com/vaadin/client/widget/escalator/RowContainer.java View File

@@ -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);
}

/**

+ 18
- 0
client/src/main/java/com/vaadin/client/widgets/Escalator.java View File

@@ -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;

@@ -2406,6 +2408,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")
@@ -2997,6 +3005,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();
@@ -4005,6 +4017,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 {

+ 48
- 0
server/src/main/java/com/vaadin/ui/GridDragSourceExtension.java View File

@@ -0,0 +1,48 @@
/*
* 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 com.vaadin.event.dnd.DragSourceExtension;
import com.vaadin.shared.ui.grid.GridDragSourceExtensionState;

/**
* Makes a Grid's rows draggable for HTML5 drag and drop functionality.
*
* @author Vaadin Ltd.
* @since
*/
public class GridDragSourceExtension extends DragSourceExtension<Grid> {

/**
* Extends a Grid and makes it's rows draggable.
*
* @param target
* Grid to be extended.
*/
public GridDragSourceExtension(Grid target) {
super(target);
}

@Override
protected GridDragSourceExtensionState getState() {
return (GridDragSourceExtensionState) super.getState();
}

@Override
protected GridDragSourceExtensionState getState(boolean markAsDirty) {
return (GridDragSourceExtensionState) super.getState(markAsDirty);
}
}

+ 33
- 0
shared/src/main/java/com/vaadin/shared/ui/grid/GridDragSourceExtensionState.java View File

@@ -0,0 +1,33 @@
/*
* 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_ROW_DATA = "grid-row-data";

}

+ 95
- 0
uitest/src/main/java/com/vaadin/tests/components/grid/GridDragAndDrop.java View File

@@ -0,0 +1,95 @@
/*
* 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;

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 dragSource = new GridDragSourceExtension(
dragSourceComponent);

Label dropTargetComponent = new Label("Drop here");
DropTargetExtension<Label> dropTarget = new DropTargetExtension<>(
dropTargetComponent);

dropTarget.addDropListener(event -> {
log(event.getTransferData(
GridDragSourceExtensionState.DATA_TYPE_ROW_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;
}
}
}

Loading…
Cancel
Save