diff options
author | Pekka Hyvönen <pekka@vaadin.com> | 2017-11-16 14:05:12 +0200 |
---|---|---|
committer | Teemu Suo-Anttila <tsuoanttila@users.noreply.github.com> | 2017-11-16 14:05:12 +0200 |
commit | ce3efd94b34c77ce470af291c501d679e2872cdd (patch) | |
tree | f5763b7ec7b44c63cc27aa3d3d8f13d579e81e95 | |
parent | 5548c5bca76504e642f543b007687beefce210a3 (diff) | |
download | vaadin-framework-ce3efd94b34c77ce470af291c501d679e2872cdd.tar.gz vaadin-framework-ce3efd94b34c77ce470af291c501d679e2872cdd.zip |
Add documentation on GridDragger (#10328)
This pathc also switches GridDragger to by default not allow drops on rows when the
grid has been sorted.
9 files changed, 208 insertions, 5 deletions
diff --git a/documentation/advanced/advanced-dragndrop.asciidoc b/documentation/advanced/advanced-dragndrop.asciidoc index 6ebf69a905..643cb859f4 100644 --- a/documentation/advanced/advanced-dragndrop.asciidoc +++ b/documentation/advanced/advanced-dragndrop.asciidoc @@ -230,6 +230,61 @@ More details can be found from the link:https://github.com/timruffles/ios-html5- It is possible to drag and drop the rows of a Grid component. This allows reordering of rows, dragging rows between different Grids, dragging rows outside of a Grid or dropping data onto rows. +In Vaadin Framework 8.2, a `GridDragger` helper has been added to make it easier for the simple cases to enable drag-and-drop support for reordering one grid's rows and moving rows between two grids with the same data type. + +=== Drag and Drop Reordering Items of a Grid (since 8.2) + +To allow the user to reorder the rows in a grid, you can use the `GridDragger` extension. It will handle configuring the grid as a drag source and drop target, and insert the dropped rows to the dropped index in the data provider, when a `ListDataProvider` is used. + +[source,java] +---- +// create a new grid backed by a list data provider +Grid<Task> taskGrid = new Grid<>("Priority Tasks", service.getTasks()); + +// grid column etc. setup omitted + +// enable DnD reordering within the grid +GridDragger<Task> gridDragger = new GridDragger<>(taskGrid); + +// disable all columns sorting so DnD reordering is always used +grid.getColumns().stream().forEach(col -> col.setSortable(false)); +---- + +The `GridDragger` uses the `DropMode.BETWEEN` by default. It doesn't not allow the user to drop data on top of a sorted grid's rows by automatically switching to `DropMode.ON_GRID` if the grid has been sorted by the user. This is because the shown drop location would not be correct due to the sorting. It is recommended that you disable the sorting for the grid, by using the `Column.setSortable` method (like above). By default, all columns are sortable when a in-memory data provider is used. If you allow the user to drop on top of a sorted grid's rows, you should scroll the dropped data to be visible with `grid.scrollToRow(index);` after drop for good UX - the `GridDragger` does not do this! + +If you want to customize the setup for the grid as a drag source or drop target, you can access and customize the handlers with the `getGridDragSource` and the `getGridDropTarget()` methods. + +For supporting other data providers, you can customize data provider updating on drop event with `setSourceDataProviderUpdater(SourceDataProviderUpdater<T> updater)` (for the source grid row removal) and `setTargetDataProviderUpdater(TargetDataProviderUpdater<T> updater)` (for the target grid row adding). The drop index calculation can be customized via `setDropIndexCalculator(DropIndexCalculator<T> dropIndexCalculator)`. + +=== Drag and Drop between two Grids (since 8.2) + +The `GridDragger` extension enables you to easily setup drag and drop moving of data between two grids. The same features apply as with the single grid reordering case in previous chapter. + +The following code snippet shows an example of allowing dragging items both ways between two grids. Note that it does not allow the user to drop the data on the same grid where the drag was started from, by setting the drop effect to `NONE` and thus the drop indicator is not shown. + +[source,java] +---- +// create grids with list data providers, and disable sorting +Grid<Person> left = createGrid(); +Grid<Person> right = createGrid(); + +GridDragger<Person> leftToRight = new GridDragger<>(left, right); +GridDragger<Person> rightToLeft = new GridDragger<>(right, left); + +// Don't show the drop indicator for drags over the same grid where the drag started +leftToRight.getGridDragSource() + .addDragStartListener(event -> rightToLeft.getGridDropTarget() + .setDropEffect(DropEffect.NONE)); +leftToRight.getGridDragSource().addDragEndListener( + event -> rightToLeft.getGridDropTarget().setDropEffect(null)); + +rightToLeft.getGridDragSource() + .addDragStartListener(event -> leftToRight.getGridDropTarget() + .setDropEffect(DropEffect.NONE)); +rightToLeft.getGridDragSource().addDragEndListener( + event -> leftToRight.getGridDropTarget().setDropEffect(null)); +---- + === Grid as a Drag Source A Grid component's rows can be made draggable by applying [classname]#GridDragSource# extension to the component. The extended Grid's rows become draggable, meaning that each row can be grabbed and moved by the mouse individually. @@ -315,6 +370,9 @@ Grid<Person> grid = new Grid<>(); // ... GridDropTarget<Person> dropTarget = new GridDropTarget<>(grid, DropMode.BETWEEN); dropTarget.setDropEffect(DropEffect.MOVE); + +// do not show drop target between rows when grid has been sorted +dropTarget.setDropAllowedOnSortedGridRows(false); ---- The _drop mode_ specifies the behaviour of the row when an element is dragged over or dropped onto it. Use `DropMode.ON_TOP` when you want to drop elements on top of a row and `DropMode.BETWEEN` when you want to drop elements between rows. `DropMode_ON_TOP_OR_BETWEEN` allows to drop on between or top rows. `DropMode.ON_GRID` (since version 8.2) does not allow dropping on the grid rows, but just into the grid, without a specific target row. diff --git a/server/src/main/java/com/vaadin/ui/Grid.java b/server/src/main/java/com/vaadin/ui/Grid.java index 4b5ab2a84b..d79fad7ec2 100644 --- a/server/src/main/java/com/vaadin/ui/Grid.java +++ b/server/src/main/java/com/vaadin/ui/Grid.java @@ -1182,6 +1182,10 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents, /** * Sets whether the user can sort this column or not. + * <p> + * By default, a grid using a in-memory data provider has its columns + * sortable by default. For a backend data provider, the columns are not + * sortable by default. * * @param sortable * {@code true} if the column can be sorted by the user; diff --git a/server/src/main/java/com/vaadin/ui/components/grid/GridDragSource.java b/server/src/main/java/com/vaadin/ui/components/grid/GridDragSource.java index c5a3b0dd94..e3482a04f2 100644 --- a/server/src/main/java/com/vaadin/ui/components/grid/GridDragSource.java +++ b/server/src/main/java/com/vaadin/ui/components/grid/GridDragSource.java @@ -43,6 +43,7 @@ import elemental.json.JsonObject; * The Grid bean type. * @author Vaadin Ltd. * @since 8.1 + * @see GridDragger */ public class GridDragSource<T> extends DragSourceExtension<Grid<T>> { diff --git a/server/src/main/java/com/vaadin/ui/components/grid/GridDragger.java b/server/src/main/java/com/vaadin/ui/components/grid/GridDragger.java index a7186a0801..a181b792ad 100644 --- a/server/src/main/java/com/vaadin/ui/components/grid/GridDragger.java +++ b/server/src/main/java/com/vaadin/ui/components/grid/GridDragger.java @@ -26,12 +26,21 @@ import com.vaadin.shared.ui.dnd.DropEffect; import com.vaadin.shared.ui.grid.DropLocation; import com.vaadin.shared.ui.grid.DropMode; import com.vaadin.ui.Grid; +import com.vaadin.ui.Grid.Column; /** - * Allows dragging rows for reordering within a Grid and between separate Grids. + * Allows dragging rows for reordering within a Grid and between two separate + * Grids when the item type is the same. * <p> * When dragging a selected row, all the visible selected rows are dragged. Note - * that ONLY currently visible rows are taken into account. + * that ONLY currently visible rows are taken into account. The drop mode for + * the target grid is by default {@link DropMode#BETWEEN}. + * <p> + * To customize the settings for either the source or the target grid, use + * {@link #getGridDragSource()} and {@link #getGridDropTarget()}.The drop target + * grid has been set to not allow drops for a target row when the grid has been + * sorted, since the visual drop target location would not match where the item + * would actually be dropped into. * <p> * <em>NOTE: this helper works only with {@link ListDataProvider} on both grids. * If you have another data provider, you should customize data provider @@ -68,6 +77,20 @@ public class GridDragger<T> implements Serializable { * Enables DnD reordering for the rows in the given grid. * <p> * {@link DropMode#BETWEEN} is used. + * <p> + * <em>NOTE:</em> this only works when the grid has a + * {@link ListDataProvider}. Use the custom handlers + * {@link #setSourceDataProviderUpdater(SourceDataProviderUpdater)} and + * {@link #setTargetDataProviderUpdater(TargetDataProviderUpdater)} for + * other data providers. + * <p> + * <em>NOTE:</em> When allowing the user to DnD reorder a grid's rows, you + * should not allow the user to sort the grid since when the grid is sorted, + * as the reordering doens't make any sense since the drop target cannot be + * shown for the correct place due to the sorting. Sorting columns is + * enabled by default for in-memory data provider grids. Sorting can be + * disabled for columns with {@link Grid#getColumns()} and + * {@link Column#setSortable(boolean)}. * * @param grid * Grid to be extended. @@ -80,11 +103,19 @@ public class GridDragger<T> implements Serializable { * Enables DnD reordering the rows in the given grid with the given drop * mode. * <p> - * <em>NOTE: this only works when the grid has a - * {@link ListDataProvider}.</em> Use the custom handlers + * <em>NOTE:</em> this only works when the grid has a + * {@link ListDataProvider}. Use the custom handlers * {@link #setSourceDataProviderUpdater(SourceDataProviderUpdater)} and * {@link #setTargetDataProviderUpdater(TargetDataProviderUpdater)} for * other data providers. + * <p> + * <em>NOTE:</em> When allowing the user to DnD reorder a grid's rows, you + * should not allow the user to sort the grid since when the grid is sorted, + * as the reordering doens't make any sense since the drop target cannot be + * shown for the correct place due to the sorting. Sorting columns is + * enabled by default for in-memory data provider grids. Sorting can be + * disabled for columns with {@link Grid#getColumns()} and + * {@link Column#setSortable(boolean)}. * * @param grid * the grid to enable row DnD reordering on @@ -159,6 +190,7 @@ public class GridDragger<T> implements Serializable { gridDragSource = new GridDragSource<>(source); gridDropTarget = new GridDropTarget<>(target, dropMode); + gridDropTarget.setDropAllowedOnSortedGridRows(false); gridDragSource.addGridDragStartListener(event -> { draggedItems = event.getDraggedItems(); @@ -277,7 +309,7 @@ public class GridDragger<T> implements Serializable { * Returns the currently dragged items captured from the source grid no drag * start event, or {@code null} if no drag active. * - * @return the currenytly dragged items or {@code null} + * @return the currently dragged items or {@code null} */ protected List<T> getDraggedItems() { return draggedItems; @@ -374,6 +406,10 @@ public class GridDragger<T> implements Serializable { // instead of using setItems or creating a new data provider, // refresh the existing one to keep filters etc. in place listDataProvider.refreshAll(); + + // if dropped to the end of the grid, the grid should scroll there so + // that the dropped row is visible, but that is just recommended in + // documentation and left for the users to take into use } private int calculateDropIndex(GridDropEvent<T> event) { diff --git a/server/src/main/java/com/vaadin/ui/components/grid/GridDropTarget.java b/server/src/main/java/com/vaadin/ui/components/grid/GridDropTarget.java index e4b175fe81..5073287c52 100644 --- a/server/src/main/java/com/vaadin/ui/components/grid/GridDropTarget.java +++ b/server/src/main/java/com/vaadin/ui/components/grid/GridDropTarget.java @@ -35,6 +35,7 @@ import com.vaadin.ui.dnd.DropTargetExtension; * Type of the Grid bean. * @author Vaadin Ltd * @since 8.1 + * @see GridDragger */ public class GridDropTarget<T> extends DropTargetExtension<Grid<T>> { diff --git a/server/src/test/java/com/vaadin/tests/server/component/grid/GridDraggerOneGridTest.java b/server/src/test/java/com/vaadin/tests/server/component/grid/GridDraggerOneGridTest.java index 6d24020e45..24e72566f4 100644 --- a/server/src/test/java/com/vaadin/tests/server/component/grid/GridDraggerOneGridTest.java +++ b/server/src/test/java/com/vaadin/tests/server/component/grid/GridDraggerOneGridTest.java @@ -45,6 +45,7 @@ public class GridDraggerOneGridTest { @Before public void setupListCase() { source = new Grid<>(); + source.addColumn(s -> s).setId("1"); dragger = new TestGridDragger(source); } @@ -203,4 +204,23 @@ public class GridDraggerOneGridTest { verifyDataProvider("1", "0", "2", "4", "3"); } + @Test + public void dropOnSortedGrid_byDefault_dropsToTheEnd() { + Assert.assertFalse( + "Default drops on sorted grid rows should not be allowed", + dragger.getGridDropTarget().isDropAllowedOnSortedGridRows()); + + source.setItems("0", "1", "2", "3", "4"); + + drop("3", DropLocation.BELOW, "1"); + + verifyDataProvider("0", "2", "3", "1", "4"); + + source.sort("1"); + + drop(null, DropLocation.EMPTY, "0"); + + verifyDataProvider("2", "3", "1", "4", "0"); + } + } diff --git a/server/src/test/java/com/vaadin/tests/server/component/grid/GridDraggerTwoGridsTest.java b/server/src/test/java/com/vaadin/tests/server/component/grid/GridDraggerTwoGridsTest.java index 0711b711df..c73641097d 100644 --- a/server/src/test/java/com/vaadin/tests/server/component/grid/GridDraggerTwoGridsTest.java +++ b/server/src/test/java/com/vaadin/tests/server/component/grid/GridDraggerTwoGridsTest.java @@ -47,6 +47,7 @@ public class GridDraggerTwoGridsTest { public void setupListCase() { source = new Grid<>(); target = new Grid<>(); + target.addColumn(s -> s).setId("1"); dragger = new TestGridDragger(source, target); target.setItems(); // setup to use list data provider @@ -249,4 +250,21 @@ public class GridDraggerTwoGridsTest { Assert.assertEquals("given drop index to target updater is wrong", 2, updaterTrigger.get()); } + + @Test + public void dropOnSortedGrid_byDefault_dropsToTheEnd() { + Assert.assertFalse( + "Default drops on sorted grid rows should not be allowed", + dragger.getGridDropTarget().isDropAllowedOnSortedGridRows()); + + source.setItems("0", "1", "2"); + target.setItems("4", "5"); + + target.sort("1"); + + drop(null, DropLocation.EMPTY, "0"); + + verifySourceDataProvider("1", "2"); + verifyTargetDataProvider("4", "5", "0"); + } } diff --git a/shared/src/main/java/com/vaadin/shared/ui/grid/DropMode.java b/shared/src/main/java/com/vaadin/shared/ui/grid/DropMode.java index 1dbafbcbc0..927cbb7516 100644 --- a/shared/src/main/java/com/vaadin/shared/ui/grid/DropMode.java +++ b/shared/src/main/java/com/vaadin/shared/ui/grid/DropMode.java @@ -55,6 +55,9 @@ public enum DropMode { * event will not contain any target row information. This is the drop * target used when the grid is completely empty. It can also be configured * to be used automatically when the user has sorted the grid. + * <p> + * When this mode is used, it also recommended to automatically scroll the + * dropped data (new rows) to be visible for the user. * * @since 8.2 */ diff --git a/uitest/src/main/java/com/vaadin/tests/components/grid/GridDraggerTwoGridsBothWays.java b/uitest/src/main/java/com/vaadin/tests/components/grid/GridDraggerTwoGridsBothWays.java new file mode 100644 index 0000000000..f07ea77930 --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/components/grid/GridDraggerTwoGridsBothWays.java @@ -0,0 +1,62 @@ +/* + * 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 com.vaadin.annotations.Theme; +import com.vaadin.annotations.Widgetset; +import com.vaadin.server.VaadinRequest; +import com.vaadin.shared.ui.dnd.DropEffect; +import com.vaadin.tests.util.Person; +import com.vaadin.ui.Grid; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Layout; +import com.vaadin.ui.components.grid.GridDragger; + +@Theme("valo") +@Widgetset("com.vaadin.DefaultWidgetSet") +public class GridDraggerTwoGridsBothWays extends AbstractGridDnD { + + @Override + protected void setup(VaadinRequest request) { + getUI().setMobileHtml5DndEnabled(true); + + Grid<Person> left = createGridAndFillWithData(25); + Grid<Person> right = createGridAndFillWithData(25); + + GridDragger<Person> leftToRight = new GridDragger<>(left, right); + GridDragger<Person> rightToLeft = new GridDragger<>(right, left); + + leftToRight.getGridDragSource() + .addDragStartListener(event -> rightToLeft.getGridDropTarget() + .setDropEffect(DropEffect.NONE)); + leftToRight.getGridDragSource().addDragEndListener( + event -> rightToLeft.getGridDropTarget().setDropEffect(null)); + + rightToLeft.getGridDragSource() + .addDragStartListener(event -> leftToRight.getGridDropTarget() + .setDropEffect(DropEffect.NONE)); + rightToLeft.getGridDragSource().addDragEndListener( + event -> leftToRight.getGridDropTarget().setDropEffect(null)); + + Layout layout = new HorizontalLayout(); + + layout.addComponent(left); + layout.addComponent(right); + layout.setWidth("100%"); + addComponent(layout); + } + +} |