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.

DragAndDropWrapper.java 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  2. @ITMillApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.ui;
  5. import java.io.IOException;
  6. import java.io.InputStream;
  7. import java.io.OutputStream;
  8. import java.io.Serializable;
  9. import java.util.HashMap;
  10. import java.util.Map;
  11. import com.vaadin.event.Transferable;
  12. import com.vaadin.event.TransferableImpl;
  13. import com.vaadin.event.dd.DragSource;
  14. import com.vaadin.event.dd.DropHandler;
  15. import com.vaadin.event.dd.DropTarget;
  16. import com.vaadin.event.dd.TargetDetails;
  17. import com.vaadin.event.dd.TargetDetailsImpl;
  18. import com.vaadin.terminal.PaintException;
  19. import com.vaadin.terminal.PaintTarget;
  20. import com.vaadin.terminal.UploadStream;
  21. import com.vaadin.terminal.gwt.client.MouseEventDetails;
  22. import com.vaadin.terminal.gwt.client.ui.VDragAndDropWrapper;
  23. import com.vaadin.terminal.gwt.client.ui.dd.HorizontalDropLocation;
  24. import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation;
  25. import com.vaadin.terminal.gwt.server.AbstractApplicationServlet;
  26. import com.vaadin.ui.DragAndDropWrapper.WrapperTransferable.Html5File;
  27. import com.vaadin.ui.Upload.Receiver;
  28. import com.vaadin.ui.Upload.UploadException;
  29. @SuppressWarnings("serial")
  30. @ClientWidget(VDragAndDropWrapper.class)
  31. public class DragAndDropWrapper extends CustomComponent implements DropTarget,
  32. DragSource {
  33. public class WrapperTransferable extends TransferableImpl {
  34. private Html5File[] files;
  35. public WrapperTransferable(Component sourceComponent,
  36. Map<String, Object> rawVariables) {
  37. super(sourceComponent, rawVariables);
  38. Integer fc = (Integer) rawVariables.get("filecount");
  39. if (fc != null) {
  40. files = new Html5File[fc];
  41. for (int i = 0; i < fc; i++) {
  42. Html5File file = new Html5File();
  43. String id = (String) rawVariables.get("fi" + i);
  44. file.name = (String) rawVariables.get("fn" + i);
  45. file.size = (Integer) rawVariables.get("fs" + i);
  46. file.type = (String) rawVariables.get("ft" + i);
  47. files[i] = file;
  48. receivers.put(id, file);
  49. }
  50. }
  51. }
  52. /**
  53. * The component in wrapper that is being dragged or null if the
  54. * transferrable is not a component (most likely an html5 drag).
  55. *
  56. * @return
  57. */
  58. public Component getDraggedComponent() {
  59. Component object = (Component) getData("component");
  60. return object;
  61. }
  62. /**
  63. * @return the mouse down event that started the drag and drop operation
  64. */
  65. public MouseEventDetails getMouseDownEvent() {
  66. return MouseEventDetails.deSerialize((String) getData("mouseDown"));
  67. }
  68. public Html5File[] getFiles() {
  69. return files;
  70. }
  71. public String getText() {
  72. String data = (String) getData("Text"); // IE, html5
  73. if (data == null) {
  74. // check for "text/plain" (webkit)
  75. data = (String) getData("text/plain");
  76. }
  77. return data;
  78. }
  79. public String getHtml() {
  80. String data = (String) getData("Html"); // IE, html5
  81. if (data == null) {
  82. // check for "text/plain" (webkit)
  83. data = (String) getData("text/html");
  84. }
  85. return data;
  86. }
  87. /**
  88. * {@link DragAndDropWrapper} can receive also files from client
  89. * computer if appropriate HTML 5 features are supported on client side.
  90. * This class wraps information about dragged file on server side.
  91. */
  92. public class Html5File implements Serializable {
  93. public String name;
  94. private int size;
  95. private Receiver receiver;
  96. private String type;
  97. public String getFileName() {
  98. return name;
  99. }
  100. public int getFileSize() {
  101. return size;
  102. }
  103. public String getType() {
  104. return type;
  105. }
  106. /**
  107. * Sets the {@link Receiver} that into which the file contents will
  108. * be written. Usage of Reveiver is similar to {@link Upload}
  109. * component.
  110. *
  111. * <p>
  112. * <em>Note!</em> receiving file contents is experimental feature
  113. * depending on HTML 5 API's. It is supported only by Firefox 3.6 at
  114. * this time.
  115. *
  116. * @param receiver
  117. * the callback that returns stream where the
  118. * implementation writes the file contents as it arrives.
  119. */
  120. public void setReceiver(Receiver receiver) {
  121. this.receiver = receiver;
  122. }
  123. }
  124. }
  125. private Map<String, Html5File> receivers = new HashMap<String, Html5File>();
  126. public class WrapperTargetDetails extends TargetDetailsImpl {
  127. public WrapperTargetDetails(Map<String, Object> rawDropData) {
  128. super(rawDropData, DragAndDropWrapper.this);
  129. }
  130. /**
  131. * @return the absolute position of wrapper on the page
  132. */
  133. public Integer getAbsoluteLeft() {
  134. return (Integer) getData("absoluteLeft");
  135. }
  136. /**
  137. *
  138. * @return the absolute position of wrapper on the page
  139. */
  140. public Integer getAbsoluteTop() {
  141. return (Integer) getData("absoluteTop");
  142. }
  143. /**
  144. * @return details about the actual event that caused the event details.
  145. * Practically mouse move or mouse up.
  146. */
  147. public MouseEventDetails getMouseEvent() {
  148. return MouseEventDetails
  149. .deSerialize((String) getData("mouseEvent"));
  150. }
  151. public VerticalDropLocation verticalDropLocation() {
  152. return VerticalDropLocation
  153. .valueOf((String) getData("verticalLocation"));
  154. }
  155. public HorizontalDropLocation horizontalDropLocation() {
  156. return HorizontalDropLocation
  157. .valueOf((String) getData("horizontalLocation"));
  158. }
  159. }
  160. public enum DragStartMode {
  161. /**
  162. * {@link DragAndDropWrapper} does not start drag events at all
  163. */
  164. NONE,
  165. /**
  166. * The component on which the drag started will be shown as drag image.
  167. */
  168. COMPONENT,
  169. /**
  170. * The whole wrapper is used as a drag image when dragging.
  171. */
  172. WRAPPER
  173. }
  174. private DragStartMode dragStartMode = DragStartMode.NONE;
  175. /**
  176. * Wraps given component in a {@link DragAndDropWrapper}.
  177. *
  178. * @param root
  179. * the component to be wrapped
  180. */
  181. public DragAndDropWrapper(Component root) {
  182. super(root);
  183. }
  184. @Override
  185. public void paintContent(PaintTarget target) throws PaintException {
  186. super.paintContent(target);
  187. target.addAttribute("dragStartMode", dragStartMode.ordinal());
  188. if (getDropHandler() != null) {
  189. getDropHandler().getAcceptCriterion().paint(target);
  190. }
  191. }
  192. private DropHandler dropHandler;
  193. public DropHandler getDropHandler() {
  194. return dropHandler;
  195. }
  196. public void setDropHandler(DropHandler dropHandler) {
  197. this.dropHandler = dropHandler;
  198. requestRepaint();
  199. }
  200. public TargetDetails translateDropTargetDetails(
  201. Map<String, Object> clientVariables) {
  202. return new WrapperTargetDetails(clientVariables);
  203. }
  204. public Transferable getTransferable(final Map<String, Object> rawVariables) {
  205. return new WrapperTransferable(this, rawVariables);
  206. }
  207. public void setDragStartMode(DragStartMode dragStartMode) {
  208. this.dragStartMode = dragStartMode;
  209. requestRepaint();
  210. }
  211. public DragStartMode getDragStartMode() {
  212. return dragStartMode;
  213. }
  214. /**
  215. * This method should only be used by Vaadin terminal implementation. This
  216. * is not end user api.
  217. *
  218. * TODO should fire progress events + end/succes events like upload. Not
  219. * critical until we have a wider browser support for HTML5 File API
  220. *
  221. * @param upstream
  222. * @param fileId
  223. * @throws UploadException
  224. */
  225. public void receiveFile(UploadStream upstream, String fileId)
  226. throws UploadException {
  227. Html5File file = receivers.get(fileId);
  228. if (file != null && file.receiver != null) {
  229. OutputStream receiveUpload = file.receiver.receiveUpload(
  230. file.getFileName(), "TODO");
  231. InputStream stream = upstream.getStream();
  232. byte[] buf = new byte[AbstractApplicationServlet.MAX_BUFFER_SIZE];
  233. int bytesRead;
  234. try {
  235. while ((bytesRead = stream.read(buf)) != -1) {
  236. receiveUpload.write(buf, 0, bytesRead);
  237. }
  238. receiveUpload.close();
  239. } catch (IOException e) {
  240. throw new UploadException(e);
  241. }
  242. // clean up the reference when file is downloaded
  243. receivers.remove(fileId);
  244. }
  245. }
  246. }