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.

advanced-dragndrop.asciidoc 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. ---
  2. title: Drag and Drop
  3. order: 12
  4. layout: page
  5. ---
  6. [[advanced.dragndrop]]
  7. = Drag and Drop
  8. ((("Drag and Drop", id="term.advanced.dragndrop", range="startofrange")))
  9. Dragging an object from one location to another by grabbing it with mouse,
  10. holding the mouse button pressed, and then releasing the button to "drop" it to
  11. the other location is a common way to move, copy, or associate objects. For
  12. example, most operating systems allow dragging and dropping files between
  13. folders or dragging a document on a program to open it. In Vaadin, it is
  14. possible to drag and drop components and parts of certain components.
  15. Dragged objects, or __transferables__, are essentially data objects. You can
  16. drag and drop rows in [classname]#Table# and nodes in [classname]#Tree#
  17. components, either within or between the components. You can also drag entire
  18. components by wrapping them inside [classname]#DragAndDropWrapper#.
  19. Dragging starts from a __drag source__, which defines the transferable.
  20. Transferables implement the [classname]#Transferable# interfaces. For trees and
  21. tables, which are bound to [classname]#Container# data sources, a node or row
  22. transferable is a reference to an [classname]#Item# in the Vaadin Data Model.
  23. Dragged components are referenced with a [classname]#WrapperTransferable#.
  24. Starting dragging does not require any client-server communication, you only
  25. need to enable dragging. All drag and drop logic occurs in two operations:
  26. determining ( __accepting__) where dropping is allowed and actually dropping.
  27. Drops can be done on a __drop target__, which implements the
  28. [classname]#DropTarget# interface. Three components implement the interface:
  29. [classname]#Tree#, [classname]#Table#, and [classname]#DragAndDropWrapper#.
  30. These accept and drop operations need to be provided in a __drop handler__.
  31. Essentially all you need to do to enable drag and drop is to enable dragging in
  32. the drag source and implement the [methodname]#getAcceptCriterion()# and
  33. [methodname]#drop()# methods in the [classname]#DropHandler# interface.
  34. The client-server architecture of Vaadin causes special requirements for the
  35. drag and drop functionality. The logic for determining where a dragged object
  36. can be dropped, that is, __accepting__ a drop, should normally be done on the
  37. client-side, in the browser. Server communications are too slow to have much of
  38. such logic on the server-side. The drag and drop feature therefore offers a
  39. number of ways to avoid the server communications to ensure a good user
  40. experience.
  41. [[advanced.dragndrop.drophandler]]
  42. == Handling Drops
  43. Most of the user-defined drag and drop logic occurs in a __drop handler__, which
  44. is provided by implementing the [methodname]#drop()# method in the
  45. [classname]#DropHandler# interface. A closely related definition is the drop
  46. accept criterion, which is defined in the [methodname]#getAcceptCriterion()#
  47. method in the same interface. It is described in
  48. <<advanced.dragndrop.acceptcriteria>> later.
  49. The [methodname]#drop()# method gets a [classname]#DragAndDropEvent# as its
  50. parameters. The event object provides references to two important object:
  51. [classname]#Transferable# and [classname]#TargetDetails#.
  52. A [classname]#Transferable# contains a reference to the object (component or
  53. data item) that is being dragged. A tree or table item is represented as a
  54. [classname]#TreeTransferable# or [classname]#TableTransferable# object, which
  55. carries the item identifier of the dragged tree or table item. These special
  56. transferables, which are bound to some data in a container, are
  57. [classname]#DataBoundTransferable#. Dragged components are represented as
  58. [classname]#WrapperTransferable# objects, as the components are wrapped in a
  59. [classname]#DragAndDropWrapper#.
  60. The [classname]#TargetDetails# object provides information about the exact
  61. location where the transferable object is being dropped. The exact class of the
  62. details object depends on the drop target and you need to cast it to the proper
  63. subclass to get more detailed information. If the target is selection component,
  64. essentially a tree or a table, the [classname]#AbstractSelectTargetDetails#
  65. object tells the item on which the drop is being made. For trees, the
  66. [classname]#TreeTargetDetails# gives some more details. For wrapped components,
  67. the information is provided in a [classname]#WrapperDropDetails# object. In
  68. addition to the target item or component, the details objects provide a __drop
  69. location__. For selection components, the location can be obtained with the
  70. [methodname]#getDropLocation()# and for wrapped components with
  71. [methodname]#verticalDropLocation()# and [methodname]#horizontalDropLocation()#.
  72. The locations are specified as either [classname]#VerticalDropLocation# or
  73. [classname]#HorizontalDropLocation# objects. The drop location objects specify
  74. whether the transferable is being dropped above, below, or directly on (at the
  75. middle of) a component or item.
  76. Dropping on a [classname]#Tree#, [classname]#Table#, and a wrapped component is
  77. explained further in the following sections.
  78. [[advanced.dragndrop.treedrop]]
  79. == Dropping Items On a [classname]#Tree#
  80. You can drag items from, to, or within a [classname]#Tree#. Making tree a drag
  81. source requires simply setting the drag mode with [methodname]#setDragMode()#.
  82. [classname]#Tree# currently supports only one drag mode,
  83. [literal]#++TreeDragMode.NODE++#, which allows dragging single tree nodes. While
  84. dragging, the dragged node is referenced with a [classname]#TreeTransferable#
  85. object, which is a [classname]#DataBoundTransferable#. The tree node is
  86. identified by the item ID of the container item.
  87. When a transferable is dropped on a tree, the drop location is stored in a
  88. [classname]#TreeTargetDetails# object, which identifies the target location by
  89. item ID of the tree node on which the drop is made. You can get the item ID with
  90. [methodname]#getItemIdOver()# method in
  91. [classname]#AbstractSelectTargetDetails#, which the
  92. [classname]#TreeTargetDetails# inherits. A drop can occur directly on or above
  93. or below a node; the exact location is a [classname]#VerticalDropLocation#,
  94. which you can get with the [methodname]#getDropLocation()# method.
  95. In the example below, we have a [classname]#Tree# and we allow reordering the
  96. tree items by drag and drop.
  97. [source, java]
  98. ----
  99. final Tree tree = new Tree("Inventory");
  100. tree.setContainerDataSource(TreeExample.createTreeContent());
  101. layout.addComponent(tree);
  102. // Expand all items
  103. for (Iterator<?> it = tree.rootItemIds().iterator(); it.hasNext();)
  104. tree.expandItemsRecursively(it.next());
  105. // Set the tree in drag source mode
  106. tree.setDragMode(TreeDragMode.NODE);
  107. // Allow the tree to receive drag drops and handle them
  108. tree.setDropHandler(new DropHandler() {
  109. public AcceptCriterion getAcceptCriterion() {
  110. return AcceptAll.get();
  111. }
  112. public void drop(DragAndDropEvent event) {
  113. // Wrapper for the object that is dragged
  114. Transferable t = event.getTransferable();
  115. // Make sure the drag source is the same tree
  116. if (t.getSourceComponent() != tree)
  117. return;
  118. TreeTargetDetails target = (TreeTargetDetails)
  119. event.getTargetDetails();
  120. // Get ids of the dragged item and the target item
  121. Object sourceItemId = t.getData("itemId");
  122. Object targetItemId = target.getItemIdOver();
  123. // On which side of the target the item was dropped
  124. VerticalDropLocation location = target.getDropLocation();
  125. HierarchicalContainer container = (HierarchicalContainer)
  126. tree.getContainerDataSource();
  127. // Drop right on an item -> make it a child
  128. if (location == VerticalDropLocation.MIDDLE)
  129. tree.setParent(sourceItemId, targetItemId);
  130. // Drop at the top of a subtree -> make it previous
  131. else if (location == VerticalDropLocation.TOP) {
  132. Object parentId = container.getParent(targetItemId);
  133. container.setParent(sourceItemId, parentId);
  134. container.moveAfterSibling(sourceItemId, targetItemId);
  135. container.moveAfterSibling(targetItemId, sourceItemId);
  136. }
  137. // Drop below another item -> make it next
  138. else if (location == VerticalDropLocation.BOTTOM) {
  139. Object parentId = container.getParent(targetItemId);
  140. container.setParent(sourceItemId, parentId);
  141. container.moveAfterSibling(sourceItemId, targetItemId);
  142. }
  143. }
  144. });
  145. ----
  146. [[advanced.dragndrop.treedrop.criteria]]
  147. === Accept Criteria for Trees
  148. [classname]#Tree# defines some specialized accept criteria for trees.
  149. [classname]#TargetInSubtree#(client-side):: Accepts if the target item is in the specified sub-tree. The sub-tree is specified by the item ID of the root of the sub-tree in the constructor. The second constructor includes a depth parameter, which specifies how deep from the given root node are drops accepted. Value [literal]#++-1++# means infinite, that is, the entire sub-tree, and is therefore the same as the simpler constructor.
  150. [classname]#TargetItemAllowsChildren#(client-side):: Accepts a drop if the tree has [methodname]#setChildrenAllowed()# enabled for the target item. The criterion does not require parameters, so the class is a singleton and can be acquired with [methodname]#Tree.TargetItemAllowsChildren.get()#. For example, the following composite criterion accepts drops only on nodes that allow children, but between all nodes:
  151. +
  152. [source, java]
  153. ----
  154. return new Or (Tree.TargetItemAllowsChildren.get(), new Not(VerticalLocationIs.MIDDLE));
  155. ----
  156. [classname]#TreeDropCriterion#(server-side):: Accepts drops on only some items, which as specified by a set of item IDs. You must extend the abstract class and implement the [methodname]#getAllowedItemIds()# to return the set. While the criterion is server-side, it is lazy-loading, so that the list of accepted target nodes is loaded only once from the server for each drag operation. See <<advanced.dragndrop.acceptcriteria>> for an example.
  157. In addition, the accept criteria defined in [classname]#AbstractSelect# are
  158. available for a [classname]#Tree#, as listed in
  159. <<advanced.dragndrop.acceptcriteria>>.
  160. [[advanced.dragndrop.tabledrop]]
  161. == Dropping Items On a [classname]#Table#
  162. You can drag items from, to, or within a [classname]#Table#. Making table a drag
  163. source requires simply setting the drag mode with [methodname]#setDragMode()#.
  164. [classname]#Table# supports dragging both single rows, with
  165. [literal]#++TableDragMode.ROW++#, and multiple rows, with
  166. [literal]#++TableDragMode.MULTIROW++#. While dragging, the dragged node or nodes
  167. are referenced with a [classname]#TreeTransferable# object, which is a
  168. [classname]#DataBoundTransferable#. Tree nodes are identified by the item IDs of
  169. the container items.
  170. When a transferable is dropped on a table, the drop location is stored in a
  171. [classname]#AbstractSelectTargetDetails# object, which identifies the target row
  172. by its item ID. You can get the item ID with [methodname]#getItemIdOver()#
  173. method. A drop can occur directly on or above or below a row; the exact location
  174. is a [classname]#VerticalDropLocation#, which you can get with the
  175. [methodname]#getDropLocation()# method from the details object.
  176. [[advanced.dragndrop.tabledrop.criteria]]
  177. === Accept Criteria for Tables
  178. [classname]#Table# defines one specialized accept criterion for tables.
  179. [classname]#TableDropCriterion#(server-side):: Accepts drops only on (or above or below) items that are specified by a set of item IDs. You must extend the abstract class and implement the [methodname]#getAllowedItemIds()# to return the set. While the criterion is server-side, it is lazy-loading, so that the list of accepted target items is loaded only once from the server for each drag operation.
  180. [[advanced.dragndrop.acceptcriteria]]
  181. == Accepting Drops
  182. ((("Drag and Drop", "Accept Criteria", id="term.advanced.dragndrop.acceptcriteria", range="startofrange")))
  183. You can not drop the objects you are dragging around just anywhere. Before a
  184. drop is possible, the specific drop location on which the mouse hovers must be
  185. __accepted__. Hovering a dragged object over an accepted location displays an
  186. __accept indicator__, which allows the user to position the drop properly. As
  187. such checks have to be done all the time when the mouse pointer moves around the
  188. drop targets, it is not feasible to send the accept requests to the server-side,
  189. so drops on a target are normally accepted by a client-side __accept
  190. criterion__.
  191. A drop handler must define the criterion on the objects which it accepts to be
  192. dropped on the target. The criterion needs to be provided in the
  193. [classname]#getAcceptCriterion()# method of the [classname]#DropHandler#
  194. interface. A criterion is represented in an [classname]#AcceptCriterion# object,
  195. which can be a composite of multiple criteria that are evaluated using logical
  196. operations. There are two basic types of criteria: __client-side__ and
  197. __server-side criteria__. The various built-in criteria allow accepting drops
  198. based on the identity of the source and target components, and on the __data
  199. flavor__ of the dragged objects.
  200. To allow dropping any transferable objects, you can return a universal accept
  201. criterion, which you can get with [methodname]#AcceptAll.get()#.
  202. [source, java]
  203. ----
  204. tree.setDropHandler(new DropHandler() {
  205. public AcceptCriterion getAcceptCriterion() {
  206. return AcceptAll.get();
  207. }
  208. ...
  209. ----
  210. [[advanced.dragndrop.acceptcriteria.client-side]]
  211. === Client-Side Criteria
  212. The __client-side criteria__, which inherit the
  213. [classname]#ClientSideCriterion#, are verified on the client-side, so server
  214. requests are not needed for verifying whether each component on which the mouse
  215. pointer hovers would accept a certain object.
  216. The following client-side criteria are define in
  217. [package]#com.vaadin.event.dd.acceptcriterion#:
  218. [classname]#AcceptAll#:: Accepts all transferables and targets.
  219. [classname]#And#:: Performs the logical AND operation on two or more client-side criteria; accepts the transferable if all the given sub-criteria accept it.
  220. [classname]#ContainsDataFlavour#:: The transferable must contain the defined data flavour.
  221. [classname]#Not#:: Performs the logical NOT operation on a client-side criterion; accepts the transferable if and only if the sub-criterion does not accept it.
  222. [classname]#Or#:: Performs the logical OR operation on two or more client-side criteria; accepts the transferable if any of the given sub-criteria accepts it.
  223. [classname]#SourceIs#:: Accepts all transferables from any of the given source components
  224. [classname]#SourceIsTarget#:: Accepts the transferable only if the source component is the same as the target. This criterion is useful for ensuring that items are dragged only within a tree or a table, and not from outside it.
  225. [classname]#TargetDetailIs#:: Accepts any transferable if the target detail, such as the item of a tree node or table row, is of the given data flavor and has the given value.
  226. In addition, target components such as [classname]#Tree# and [classname]#Table#
  227. define some component-specific client-side accept criteria. See
  228. <<advanced.dragndrop.treedrop>> for more details.
  229. [classname]#AbstractSelect# defines the following criteria for all selection
  230. components, including [classname]#Tree# and [classname]#Table#.
  231. [classname]#AcceptItem#:: Accepts only specific items from a specific selection component. The selection component, which must inherit [classname]#AbstractSelect#, is given as the first parameter for the constructor. It is followed by a list of allowed item identifiers in the drag source.
  232. [classname]#AcceptItem.ALL#:: Accepts all transferables as long as they are items.
  233. [classname]#TargetItemIs#:: Accepts all drops on the specified target items. The constructor requires the target component ( [classname]#AbstractSelect#) followed by a list of allowed item identifiers.
  234. [classname]#VerticalLocationIs.MIDDLE#,[classname]#TOP#, and[classname]#BOTTOM#:: The three static criteria accepts drops on, above, or below an item. For example, you could accept drops only in between items with the following:
  235. [source, java]
  236. ----
  237. public AcceptCriterion getAcceptCriterion() {
  238. return new Not(VerticalLocationIs.MIDDLE);
  239. }
  240. ----
  241. [[advanced.dragndrop.acceptcriteria.server-side]]
  242. === Server-Side Criteria
  243. The __server-side criteria__ are verified on the server-side with the
  244. [methodname]#accept()# method of the [classname]#ServerSideCriterion# class.
  245. This allows fully programmable logic for accepting drops, but the negative side
  246. is that it causes a very large amount of server requests. A request is made for
  247. every target position on which the pointer hovers. This problem is eased in many
  248. cases by the component-specific lazy loading criteria
  249. [classname]#TableDropCriterion# and [classname]#TreeDropCriterion#. They do the
  250. server visit once for each drag and drop operation and return all accepted rows
  251. or nodes for current [classname]#Transferable# at once.
  252. The [methodname]#accept()# method gets the drag event as a parameter so it can
  253. perform its logic much like in [methodname]#drop()#.
  254. [source, java]
  255. ----
  256. public AcceptCriterion getAcceptCriterion() {
  257. // Server-side accept criterion that allows drops on any other
  258. // location except on nodes that may not have children
  259. ServerSideCriterion criterion = new ServerSideCriterion() {
  260. public boolean accept(DragAndDropEvent dragEvent) {
  261. TreeTargetDetails target = (TreeTargetDetails)
  262. dragEvent.getTargetDetails();
  263. // The tree item on which the load hovers
  264. Object targetItemId = target.getItemIdOver();
  265. // On which side of the target the item is hovered
  266. VerticalDropLocation location = target.getDropLocation();
  267. if (location == VerticalDropLocation.MIDDLE)
  268. if (! tree.areChildrenAllowed(targetItemId))
  269. return false; // Not accepted
  270. return true; // Accept everything else
  271. }
  272. };
  273. return criterion;
  274. }
  275. ----
  276. The server-side criteria base class [classname]#ServerSideCriterion# provides a
  277. generic [methodname]#accept()# method. The more specific
  278. [classname]#TableDropCriterion# and [classname]#TreeDropCriterion# are
  279. conveniency extensions that allow definiting allowed drop targets as a set of
  280. items. They also provide some optimization by lazy loading, which reduces server
  281. communications significantly.
  282. [source, java]
  283. ----
  284. public AcceptCriterion getAcceptCriterion() {
  285. // Server-side accept criterion that allows drops on any
  286. // other tree node except on node that may not have children
  287. TreeDropCriterion criterion = new TreeDropCriterion() {
  288. @Override
  289. protected Set<Object> getAllowedItemIds(
  290. DragAndDropEvent dragEvent, Tree tree) {
  291. HashSet<Object> allowed = new HashSet<Object>();
  292. for (Iterator<Object> i =
  293. tree.getItemIds().iterator(); i.hasNext();) {
  294. Object itemId = i.next();
  295. if (tree.hasChildren(itemId))
  296. allowed.add(itemId);
  297. }
  298. return allowed;
  299. }
  300. };
  301. return criterion;
  302. }
  303. ----
  304. [[advanced.dragndrop.acceptcriteria.indicators]]
  305. === Accept Indicators
  306. When a dragged object hovers on a drop target, an __accept indicator__ is
  307. displayed to show whether or not the location is accepted. For
  308. [parameter]#MIDDLE# location, the indicator is a box around the target (tree
  309. node, table row, or component). For vertical drop locations, the accepted
  310. locations are shown as horizontal lines, and for horizontal drop locations as
  311. vertical lines.
  312. For [classname]#DragAndDropWrapper# drop targets, you can disable the accept
  313. indicators or __drag hints__ with the [parameter]#no-vertical-drag-hints#,
  314. [parameter]#no-horizontal-drag-hints#, and [parameter]#no-box-drag-hints#
  315. styles. You need to add the styles to the __layout that contains__ the wrapper,
  316. not to the wrapper itself.
  317. [source, java]
  318. ----
  319. // Have a wrapper
  320. DragAndDropWrapper wrapper = new DragAndDropWrapper(c);
  321. layout.addComponent(wrapper);
  322. // Disable the hints
  323. layout.addStyleName("no-vertical-drag-hints");
  324. layout.addStyleName("no-horizontal-drag-hints");
  325. layout.addStyleName("no-box-drag-hints");
  326. ----
  327. (((range="endofrange", startref="term.advanced.dragndrop.acceptcriteria")))
  328. [[advanced.dragndrop.dragging]]
  329. == Dragging Components
  330. Dragging a component requires wrapping the source component within a
  331. [classname]#DragAndDropWrapper#. You can then allow dragging by putting the
  332. wrapper (and the component) in drag mode with [methodname]#setDragStartMode()#.
  333. The method supports two drag modes: [parameter]#DragStartMode.WRAPPER# and
  334. [parameter]#DragStartMode.COMPONENT#, which defines whether the entire wrapper
  335. is shown as the drag image while dragging or just the wrapped component.
  336. [source, java]
  337. ----
  338. // Have a component to drag
  339. final Button button = new Button("An Absolute Button");
  340. // Put the component in a D&D wrapper and allow dragging it
  341. final DragAndDropWrapper buttonWrap = new DragAndDropWrapper(button);
  342. buttonWrap.setDragStartMode(DragStartMode.COMPONENT);
  343. // Set the wrapper to wrap tightly around the component
  344. buttonWrap.setSizeUndefined();
  345. // Add the wrapper, not the component, to the layout
  346. layout.addComponent(buttonWrap, "left: 50px; top: 50px;");
  347. ----
  348. The default height of [classname]#DragAndDropWrapper# is undefined, but the
  349. default width is 100%. If you want to ensure that the wrapper fits tightly
  350. around the wrapped component, you should call [methodname]#setSizeUndefined()#
  351. for the wrapper. Doing so, you should make sure that the wrapped component does
  352. not have a relative size, which would cause a paradox.
  353. Dragged components are referenced in the [classname]#WrapperTransferable#. You
  354. can get the reference to the dragged component with
  355. [methodname]#getDraggedComponent()#. The method will return [literal]#++null++#
  356. if the transferable is not a component. Also HTML 5 drags (see later) are held
  357. in wrapper transferables.
  358. [[advanced.dragndrop.drop-on-component]]
  359. == Dropping on a Component
  360. Drops on a component are enabled by wrapping the component in a
  361. [classname]#DragAndDropWrapper#. The wrapper is an ordinary component; the
  362. constructor takes the wrapped component as a parameter. You just need to define
  363. the [classname]#DropHandler# for the wrapper with
  364. [methodname]#setDropHandler()#.
  365. In the following example, we allow moving components in an absolute layout.
  366. Details on the drop handler are given later.
  367. [source, java]
  368. ----
  369. // A layout that allows moving its contained components
  370. // by dragging and dropping them
  371. final AbsoluteLayout absLayout = new AbsoluteLayout();
  372. absLayout.setWidth("100%");
  373. absLayout.setHeight("400px");
  374. ... put some (wrapped) components in the layout ...
  375. // Wrap the layout to allow handling drops
  376. DragAndDropWrapper layoutWrapper =
  377. new DragAndDropWrapper(absLayout);
  378. // Handle moving components within the AbsoluteLayout
  379. layoutWrapper.setDropHandler(new DropHandler() {
  380. public AcceptCriterion getAcceptCriterion() {
  381. return AcceptAll.get();
  382. }
  383. public void drop(DragAndDropEvent event) {
  384. ...
  385. }
  386. });
  387. ----
  388. [[advanced.dragndrop.drop-on-component.details]]
  389. === Target Details for Wrapped Components
  390. The drop handler receives the drop target details in a
  391. [classname]#WrapperTargetDetails# object, which implements the
  392. [classname]#TargetDetails# interface.
  393. [source, java]
  394. ----
  395. public void drop(DragAndDropEvent event) {
  396. WrapperTransferable t =
  397. (WrapperTransferable) event.getTransferable();
  398. WrapperTargetDetails details =
  399. (WrapperTargetDetails) event.getTargetDetails();
  400. ----
  401. The wrapper target details include a [classname]#MouseEventDetails# object,
  402. which you can get with [methodname]#getMouseEvent()#. You can use it to get the
  403. mouse coordinates for the position where the mouse button was released and the
  404. drag ended. Similarly, you can find out the drag start position from the
  405. transferable object (if it is a [classname]#WrapperTransferable#) with
  406. [methodname]#getMouseDownEvent()#.
  407. [source, java]
  408. ----
  409. // Calculate the drag coordinate difference
  410. int xChange = details.getMouseEvent().getClientX()
  411. - t.getMouseDownEvent().getClientX();
  412. int yChange = details.getMouseEvent().getClientY()
  413. - t.getMouseDownEvent().getClientY();
  414. // Move the component in the absolute layout
  415. ComponentPosition pos =
  416. absLayout.getPosition(t.getSourceComponent());
  417. pos.setLeftValue(pos.getLeftValue() + xChange);
  418. pos.setTopValue(pos.getTopValue() + yChange);
  419. ----
  420. You can get the absolute x and y coordinates of the target wrapper with
  421. [methodname]#getAbsoluteLeft()# and [methodname]#getAbsoluteTop()#, which allows
  422. you to translate the absolute mouse coordinates to coordinates relative to the
  423. wrapper. Notice that the coordinates are really the position of the wrapper, not
  424. the wrapped component; the wrapper reserves some space for the accept
  425. indicators.
  426. The [methodname]#verticalDropLocation()# and
  427. [methodname]#horizontalDropLocation()# return the more detailed drop location in
  428. the target.
  429. [[advanced.dragndrop.external]]
  430. == Dragging Files from Outside the Browser
  431. The [classname]#DragAndDropWrapper# allows dragging files from outside the
  432. browser and dropping them on a component wrapped in the wrapper. Dropped files
  433. are automatically uploaded to the application and can be acquired from the
  434. wrapper with [methodname]#getFiles()#. The files are represented as
  435. [classname]#Html5File# objects as defined in the inner class. You can define an
  436. upload [classname]#Receiver# to receive the content of a file to an
  437. [classname]#OutputStream#.
  438. Dragging and dropping files to browser is supported in HTML 5 and requires a
  439. compatible browser, such as Mozilla Firefox 3.6 or newer.
  440. (((range="endofrange", startref="term.advanced.dragndrop")))