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.

GridDragSource.java 8.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. * Copyright 2000-2018 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.ui.components.grid;
  17. import java.util.HashMap;
  18. import java.util.List;
  19. import java.util.Map;
  20. import java.util.stream.Collectors;
  21. import com.vaadin.data.provider.DataGenerator;
  22. import com.vaadin.server.SerializableFunction;
  23. import com.vaadin.shared.Registration;
  24. import com.vaadin.shared.ui.dnd.DragSourceState;
  25. import com.vaadin.shared.ui.dnd.DropEffect;
  26. import com.vaadin.shared.ui.grid.GridDragSourceRpc;
  27. import com.vaadin.shared.ui.grid.GridDragSourceState;
  28. import com.vaadin.ui.Grid;
  29. import com.vaadin.ui.dnd.DragSourceExtension;
  30. import elemental.json.Json;
  31. import elemental.json.JsonObject;
  32. /**
  33. * Makes a Grid's rows draggable for HTML5 drag and drop functionality.
  34. * <p>
  35. * When dragging a selected row, all the visible selected rows are dragged. Note
  36. * that ONLY visible rows are taken into account.
  37. *
  38. * @param <T>
  39. * The Grid bean type.
  40. * @author Vaadin Ltd.
  41. * @since 8.1
  42. * @see GridRowDragger
  43. */
  44. public class GridDragSource<T> extends DragSourceExtension<Grid<T>> {
  45. /**
  46. * Drag data generator that appends drag data to each row.
  47. */
  48. private DataGenerator<T> dragDataGenerator;
  49. /**
  50. * Collection of drag data generator functions. Functions are executed for
  51. * each row and results are stored under their corresponding key.
  52. */
  53. private final Map<String, SerializableFunction<T, String>> generatorFunctions;
  54. /**
  55. * Default drag data generator for Grid. It creates a list of row values
  56. * separated by a tabulator character ({@code \t}).
  57. *
  58. * <pre>
  59. * "column1_value\tcolumn2_value\t ... columnN_value"
  60. * </pre>
  61. */
  62. private final SerializableFunction<T, String> defaultGridGenerator = item -> {
  63. StringBuilder generatedValue = new StringBuilder();
  64. getParent().getColumns().forEach(column -> {
  65. generatedValue.append("\t"); // Tab separated values
  66. generatedValue.append(column.getValueProvider().apply(item));
  67. });
  68. return generatedValue.substring(1);
  69. };
  70. /**
  71. * Extends a Grid and makes it's rows draggable.
  72. *
  73. * @param target
  74. * Grid to be extended.
  75. */
  76. public GridDragSource(Grid<T> target) {
  77. super(target);
  78. // Create drag data generator
  79. dragDataGenerator = this::generateDragData;
  80. // Add drag data generator to Grid
  81. target.getDataCommunicator().addDataGenerator(dragDataGenerator);
  82. generatorFunctions = new HashMap<>();
  83. // Set default generator function for "text" parameter
  84. generatorFunctions.put(DragSourceState.DATA_TYPE_TEXT,
  85. defaultGridGenerator);
  86. }
  87. /**
  88. * Gets the grid this extension has been attached to.
  89. *
  90. * @return the grid for this extension
  91. * @since 8.2
  92. */
  93. public Grid<T> getGrid() {
  94. return getParent();
  95. }
  96. @Override
  97. protected void registerDragSourceRpc() {
  98. registerRpc(new GridDragSourceRpc() {
  99. @Override
  100. public void dragStart(List<String> draggedItemKeys) {
  101. GridDragStartEvent<T> event = new GridDragStartEvent<>(
  102. getParent(), getState(false).effectAllowed,
  103. getDraggedItems(getParent(), draggedItemKeys));
  104. fireEvent(event);
  105. }
  106. @Override
  107. public void dragEnd(DropEffect dropEffect,
  108. List<String> draggedItemKeys) {
  109. GridDragEndEvent<T> event = new GridDragEndEvent<>(getParent(),
  110. dropEffect,
  111. getDraggedItems(getParent(), draggedItemKeys));
  112. fireEvent(event);
  113. }
  114. });
  115. }
  116. /**
  117. * Collects the dragged items of a Grid given the list of item keys.
  118. */
  119. private List<T> getDraggedItems(Grid<T> grid,
  120. List<String> draggedItemKeys) {
  121. if (draggedItemKeys == null || draggedItemKeys.isEmpty()) {
  122. throw new IllegalStateException(
  123. "The drag event does not contain dragged items");
  124. }
  125. return draggedItemKeys.stream()
  126. .map(key -> grid.getDataCommunicator().getKeyMapper().get(key))
  127. .collect(Collectors.toList());
  128. }
  129. /**
  130. * Drag data generator. Appends drag data to row data json if generator
  131. * function(s) are set by the user of this extension.
  132. *
  133. * @param item
  134. * Row item for data generation.
  135. * @param jsonObject
  136. * Row data in json format.
  137. */
  138. private void generateDragData(T item, JsonObject jsonObject) {
  139. JsonObject generatedValues = Json.createObject();
  140. generatorFunctions.forEach((type, generator) -> generatedValues
  141. .put(type, generator.apply(item)));
  142. jsonObject.put(GridDragSourceState.JSONKEY_DRAG_DATA, generatedValues);
  143. }
  144. /**
  145. * Sets a generator function for customizing drag data. The generated value
  146. * will be accessible using the same {@code type} as the generator is set
  147. * here. The function is executed for each item in the Grid during data
  148. * generation. Return a {@link String} to be appended to the row as {@code
  149. * type} data.
  150. * <p>
  151. * Example, building a JSON object that contains the item's values:
  152. *
  153. * <pre>
  154. * dragSourceExtension.setDragDataGenerator("application/json", item ->
  155. * {
  156. * StringBuilder builder = new StringBuilder();
  157. * builder.append("{");
  158. * getParent().getColumns().forEach(column -> {
  159. * builder.append("\"" + column.getCaption() + "\"");
  160. * builder.append(":");
  161. * builder.append("\"" + column.getValueProvider().apply(item) + "\"");
  162. * builder.append(",");
  163. * });
  164. * builder.setLength(builder.length() - 1); // Remove last comma
  165. * builder.append("}");
  166. * return builder.toString();
  167. * }
  168. * </pre>
  169. *
  170. * @param type
  171. * Type of the generated data. The generated value will be
  172. * accessible during drop using this type.
  173. * @param generator
  174. * Function to be executed on row data generation.
  175. */
  176. public void setDragDataGenerator(String type,
  177. SerializableFunction<T, String> generator) {
  178. generatorFunctions.put(type, generator);
  179. }
  180. /**
  181. * Remove the generator function set for the given type.
  182. *
  183. * @param type
  184. * Type of the generator to be removed.
  185. */
  186. public void clearDragDataGenerator(String type) {
  187. generatorFunctions.remove(type);
  188. }
  189. /**
  190. * Returns the drag data generator function for the given type.
  191. *
  192. * @param type
  193. * Type of the generated data.
  194. * @return Drag data generator function for the given type.
  195. */
  196. public SerializableFunction<T, String> getDragDataGenerator(String type) {
  197. return generatorFunctions.get(type);
  198. }
  199. /**
  200. * Attaches dragstart listener for the current drag source grid.
  201. *
  202. * @param listener
  203. * Listener to handle the dragstart event.
  204. * @return Handle to be used to remove this listener.
  205. * @see GridDragStartEvent
  206. */
  207. public Registration addGridDragStartListener(
  208. GridDragStartListener<T> listener) {
  209. return addListener(DragSourceState.EVENT_DRAGSTART,
  210. GridDragStartEvent.class, listener,
  211. GridDragStartListener.DRAG_START_METHOD);
  212. }
  213. /**
  214. * Attaches dragend listener for the current drag source grid.
  215. *
  216. * @param listener
  217. * Listener to handle the dragend event.
  218. * @return Handle to be used to remove this listener.
  219. * @see GridDragEndEvent
  220. */
  221. public Registration addGridDragEndListener(
  222. GridDragEndListener<T> listener) {
  223. return addListener(DragSourceState.EVENT_DRAGEND,
  224. GridDragEndEvent.class, listener,
  225. GridDragEndListener.DRAG_END_METHOD);
  226. }
  227. @Override
  228. public void remove() {
  229. getParent().getDataCommunicator()
  230. .removeDataGenerator(dragDataGenerator);
  231. super.remove();
  232. }
  233. @Override
  234. protected GridDragSourceState getState() {
  235. return (GridDragSourceState) super.getState();
  236. }
  237. @Override
  238. protected GridDragSourceState getState(boolean markAsDirty) {
  239. return (GridDragSourceState) super.getState(markAsDirty);
  240. }
  241. }