You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GridDragSourceExtensionConnector.java 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /*
  2. * Copyright 2000-2016 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.client.connectors.grid;
  17. import java.util.ArrayList;
  18. import java.util.List;
  19. import java.util.stream.Collectors;
  20. import com.google.gwt.dom.client.TableRowElement;
  21. import com.vaadin.client.ServerConnector;
  22. import com.vaadin.client.extensions.DragSourceExtensionConnector;
  23. import com.vaadin.client.widget.escalator.RowContainer;
  24. import com.vaadin.client.widget.grid.selection.SelectionModel;
  25. import com.vaadin.client.widgets.Escalator;
  26. import com.vaadin.client.widgets.Grid;
  27. import com.vaadin.shared.Range;
  28. import com.vaadin.shared.ui.Connect;
  29. import com.vaadin.shared.ui.dnd.DropEffect;
  30. import com.vaadin.shared.ui.grid.GridDragSourceExtensionRpc;
  31. import com.vaadin.shared.ui.grid.GridDragSourceExtensionState;
  32. import com.vaadin.shared.ui.grid.GridState;
  33. import com.vaadin.ui.GridDragSourceExtension;
  34. import elemental.events.Event;
  35. import elemental.json.Json;
  36. import elemental.json.JsonArray;
  37. import elemental.json.JsonObject;
  38. /**
  39. * Adds HTML5 drag and drop functionality to a {@link com.vaadin.client.widgets.Grid
  40. * Grid}'s rows. This is the client side counterpart of {@link
  41. * GridDragSourceExtension}.
  42. *
  43. * @author Vaadin Ltd
  44. * @since
  45. */
  46. @Connect(GridDragSourceExtension.class)
  47. public class GridDragSourceExtensionConnector extends
  48. DragSourceExtensionConnector {
  49. private GridConnector gridConnector;
  50. /**
  51. * List of dragged item keys.
  52. */
  53. private List<String> draggedItemKeys;
  54. @Override
  55. protected void extend(ServerConnector target) {
  56. this.gridConnector = (GridConnector) target;
  57. // Set newly added rows draggable
  58. getGridBody().setNewEscalatorRowCallback(
  59. rows -> rows.forEach(this::setDraggable));
  60. // Add drag listeners to body element
  61. addDragListeners(getGridBody().getElement());
  62. }
  63. @Override
  64. protected void onDragStart(Event event) {
  65. // Collect the keys of dragged rows
  66. draggedItemKeys = getDraggedRows(event).stream()
  67. .map(row -> row.getString(GridState.JSONKEY_ROWKEY))
  68. .collect(Collectors.toList());
  69. super.onDragStart(event);
  70. }
  71. @Override
  72. protected String createDataTransferText(Event dragStartEvent) {
  73. JsonArray dragData = toJsonArray(
  74. getDraggedRows(dragStartEvent).stream().map(this::getDragData)
  75. .collect(Collectors.toList()));
  76. return dragData.toJson();
  77. }
  78. @Override
  79. protected void sendDragStartEventToServer(Event dragStartEvent) {
  80. // Start server RPC with dragged item keys
  81. getRpcProxy(GridDragSourceExtensionRpc.class)
  82. .dragStart(draggedItemKeys);
  83. }
  84. private List<JsonObject> getDraggedRows(Event dragStartEvent) {
  85. List<JsonObject> draggedRows = new ArrayList<>();
  86. if (dragStartEvent.getTarget() instanceof TableRowElement) {
  87. TableRowElement row = (TableRowElement) dragStartEvent.getTarget();
  88. int rowIndex = ((Escalator.AbstractRowContainer) getGridBody())
  89. .getLogicalRowIndex(row);
  90. JsonObject rowData = gridConnector.getDataSource().getRow(rowIndex);
  91. if (dragMultipleRows(rowData)) {
  92. getSelectedVisibleRows().forEach(draggedRows::add);
  93. } else {
  94. draggedRows.add(rowData);
  95. }
  96. }
  97. return draggedRows;
  98. }
  99. @Override
  100. protected void onDragEnd(Event event) {
  101. super.onDragEnd(event);
  102. // Clear item key list
  103. draggedItemKeys = null;
  104. }
  105. @Override
  106. protected void sendDragEndEventToServer(Event dragEndEvent,
  107. DropEffect dropEffect) {
  108. // Send server RPC with dragged item keys
  109. getRpcProxy(GridDragSourceExtensionRpc.class)
  110. .dragEnd(dropEffect, draggedItemKeys);
  111. }
  112. /**
  113. * Tells if multiple rows are dragged. Returns true if multiple selection is
  114. * allowed and a selected row is dragged.
  115. *
  116. * @param draggedRow
  117. * Data of dragged row.
  118. * @return {@code true} if multiple rows are dragged, {@code false}
  119. * otherwise.
  120. */
  121. private boolean dragMultipleRows(JsonObject draggedRow) {
  122. SelectionModel<JsonObject> selectionModel = getGrid()
  123. .getSelectionModel();
  124. return selectionModel.isSelectionAllowed()
  125. && selectionModel instanceof MultiSelectionModelConnector.MultiSelectionModel
  126. && selectionModel.isSelected(draggedRow);
  127. }
  128. /**
  129. * Collects the data of all selected visible rows.
  130. *
  131. * @return List of data of all selected visible rows.
  132. */
  133. private List<JsonObject> getSelectedVisibleRows() {
  134. return getSelectedRowsInRange(getEscalator().getVisibleRowRange());
  135. }
  136. /**
  137. * Get all selected rows from a subset of rows defined by {@code range}.
  138. *
  139. * @param range
  140. * Range of indexes.
  141. * @return List of data of all selected rows in the given range.
  142. */
  143. private List<JsonObject> getSelectedRowsInRange(Range range) {
  144. List<JsonObject> selectedRows = new ArrayList<>();
  145. for (int i = range.getStart(); i < range.getEnd(); i++) {
  146. JsonObject row = gridConnector.getDataSource().getRow(i);
  147. if (SelectionModel.isItemSelected(row)) {
  148. selectedRows.add(row);
  149. }
  150. }
  151. return selectedRows;
  152. }
  153. /**
  154. * Converts a list of {@link JsonObject}s to a {@link JsonArray}.
  155. *
  156. * @param objects
  157. * List of json objects.
  158. * @return Json array containing all json objects.
  159. */
  160. private JsonArray toJsonArray(List<JsonObject> objects) {
  161. JsonArray array = Json.createArray();
  162. for (int i = 0; i < objects.size(); i++) {
  163. array.set(i, objects.get(i));
  164. }
  165. return array;
  166. }
  167. /**
  168. * Gets drag data from the row data if exists or returns complete row data
  169. * otherwise.
  170. *
  171. * @param row
  172. * Row data.
  173. * @return Drag data if present or row data otherwise.
  174. */
  175. private JsonObject getDragData(JsonObject row) {
  176. return row.hasKey(GridDragSourceExtensionState.JSONKEY_DRAG_DATA)
  177. ? row.getObject(GridDragSourceExtensionState.JSONKEY_DRAG_DATA)
  178. : row;
  179. }
  180. @Override
  181. public void onUnregister() {
  182. super.onUnregister();
  183. // Remove draggable from all row elements in the escalator
  184. Range visibleRange = getEscalator().getVisibleRowRange();
  185. for (int i = visibleRange.getStart(); i < visibleRange.getEnd(); i++) {
  186. removeDraggable(getGridBody().getRowElement(i));
  187. }
  188. // Remove drag listeners from body element
  189. removeDragListeners(getGridBody().getElement());
  190. // Remove callback for newly added rows
  191. getGridBody().setNewEscalatorRowCallback(null);
  192. }
  193. private Grid<JsonObject> getGrid() {
  194. return gridConnector.getWidget();
  195. }
  196. private Escalator getEscalator() {
  197. return getGrid().getEscalator();
  198. }
  199. private RowContainer.BodyRowContainer getGridBody() {
  200. return getEscalator().getBody();
  201. }
  202. @Override
  203. public GridDragSourceExtensionState getState() {
  204. return (GridDragSourceExtensionState) super.getState();
  205. }
  206. }