summaryrefslogtreecommitdiffstats
path: root/documentation/advanced/advanced-dragndrop.asciidoc
diff options
context:
space:
mode:
Diffstat (limited to 'documentation/advanced/advanced-dragndrop.asciidoc')
-rw-r--r--documentation/advanced/advanced-dragndrop.asciidoc567
1 files changed, 0 insertions, 567 deletions
diff --git a/documentation/advanced/advanced-dragndrop.asciidoc b/documentation/advanced/advanced-dragndrop.asciidoc
deleted file mode 100644
index 69335c6369..0000000000
--- a/documentation/advanced/advanced-dragndrop.asciidoc
+++ /dev/null
@@ -1,567 +0,0 @@
----
-title: Drag and Drop
-order: 12
-layout: page
----
-
-[[advanced.dragndrop]]
-= Drag and Drop
-
-((("Drag and Drop", id="term.advanced.dragndrop", range="startofrange")))
-
-
-Dragging an object from one location to another by grabbing it with mouse,
-holding the mouse button pressed, and then releasing the button to "drop" it to
-the other location is a common way to move, copy, or associate objects. For
-example, most operating systems allow dragging and dropping files between
-folders or dragging a document on a program to open it. In Vaadin, it is
-possible to drag and drop components and parts of certain components.
-
-Dragged objects, or __transferables__, are essentially data objects. You can
-drag and drop rows in [classname]#Table# and nodes in [classname]#Tree#
-components, either within or between the components. You can also drag entire
-components by wrapping them inside [classname]#DragAndDropWrapper#.
-
-Dragging starts from a __drag source__, which defines the transferable.
-Transferables implement the [classname]#Transferable# interfaces. For trees and
-tables, which are bound to [classname]#Container# data sources, a node or row
-transferable is a reference to an [classname]#Item# in the Vaadin Data Model.
-Dragged components are referenced with a [classname]#WrapperTransferable#.
-Starting dragging does not require any client-server communication, you only
-need to enable dragging. All drag and drop logic occurs in two operations:
-determining ( __accepting__) where dropping is allowed and actually dropping.
-Drops can be done on a __drop target__, which implements the
-[classname]#DropTarget# interface. Three components implement the interface:
-[classname]#Tree#, [classname]#Table#, and [classname]#DragAndDropWrapper#.
-These accept and drop operations need to be provided in a __drop handler__.
-Essentially all you need to do to enable drag and drop is to enable dragging in
-the drag source and implement the [methodname]#getAcceptCriterion()# and
-[methodname]#drop()# methods in the [classname]#DropHandler# interface.
-
-The client-server architecture of Vaadin causes special requirements for the
-drag and drop functionality. The logic for determining where a dragged object
-can be dropped, that is, __accepting__ a drop, should normally be done on the
-client-side, in the browser. Server communications are too slow to have much of
-such logic on the server-side. The drag and drop feature therefore offers a
-number of ways to avoid the server communications to ensure a good user
-experience.
-
-[[advanced.dragndrop.drophandler]]
-== Handling Drops
-
-Most of the user-defined drag and drop logic occurs in a __drop handler__, which
-is provided by implementing the [methodname]#drop()# method in the
-[classname]#DropHandler# interface. A closely related definition is the drop
-accept criterion, which is defined in the [methodname]#getAcceptCriterion()#
-method in the same interface. It is described in
-<<advanced.dragndrop.acceptcriteria>> later.
-
-The [methodname]#drop()# method gets a [classname]#DragAndDropEvent# as its
-parameters. The event object provides references to two important object:
-[classname]#Transferable# and [classname]#TargetDetails#.
-
-A [classname]#Transferable# contains a reference to the object (component or
-data item) that is being dragged. A tree or table item is represented as a
-[classname]#TreeTransferable# or [classname]#TableTransferable# object, which
-carries the item identifier of the dragged tree or table item. These special
-transferables, which are bound to some data in a container, are
-[classname]#DataBoundTransferable#. Dragged components are represented as
-[classname]#WrapperTransferable# objects, as the components are wrapped in a
-[classname]#DragAndDropWrapper#.
-
-The [classname]#TargetDetails# object provides information about the exact
-location where the transferable object is being dropped. The exact class of the
-details object depends on the drop target and you need to cast it to the proper
-subclass to get more detailed information. If the target is selection component,
-essentially a tree or a table, the [classname]#AbstractSelectTargetDetails#
-object tells the item on which the drop is being made. For trees, the
-[classname]#TreeTargetDetails# gives some more details. For wrapped components,
-the information is provided in a [classname]#WrapperDropDetails# object. In
-addition to the target item or component, the details objects provide a __drop
-location__. For selection components, the location can be obtained with the
-[methodname]#getDropLocation()# and for wrapped components with
-[methodname]#verticalDropLocation()# and [methodname]#horizontalDropLocation()#.
-The locations are specified as either [classname]#VerticalDropLocation# or
-[classname]#HorizontalDropLocation# objects. The drop location objects specify
-whether the transferable is being dropped above, below, or directly on (at the
-middle of) a component or item.
-
-Dropping on a [classname]#Tree#, [classname]#Table#, and a wrapped component is
-explained further in the following sections.
-
-
-[[advanced.dragndrop.treedrop]]
-== Dropping Items On a [classname]#Tree#
-
-You can drag items from, to, or within a [classname]#Tree#. Making tree a drag
-source requires simply setting the drag mode with [methodname]#setDragMode()#.
-[classname]#Tree# currently supports only one drag mode,
-[literal]#++TreeDragMode.NODE++#, which allows dragging single tree nodes. While
-dragging, the dragged node is referenced with a [classname]#TreeTransferable#
-object, which is a [classname]#DataBoundTransferable#. The tree node is
-identified by the item ID of the container item.
-
-When a transferable is dropped on a tree, the drop location is stored in a
-[classname]#TreeTargetDetails# object, which identifies the target location by
-item ID of the tree node on which the drop is made. You can get the item ID with
-[methodname]#getItemIdOver()# method in
-[classname]#AbstractSelectTargetDetails#, which the
-[classname]#TreeTargetDetails# inherits. A drop can occur directly on or above
-or below a node; the exact location is a [classname]#VerticalDropLocation#,
-which you can get with the [methodname]#getDropLocation()# method.
-
-In the example below, we have a [classname]#Tree# and we allow reordering the
-tree items by drag and drop.
-
-
-[source, java]
-----
-final Tree tree = new Tree("Inventory");
-tree.setContainerDataSource(TreeExample.createTreeContent());
-layout.addComponent(tree);
-
-// Expand all items
-for (Iterator<?> it = tree.rootItemIds().iterator(); it.hasNext();)
- tree.expandItemsRecursively(it.next());
-
-// Set the tree in drag source mode
-tree.setDragMode(TreeDragMode.NODE);
-
-// Allow the tree to receive drag drops and handle them
-tree.setDropHandler(new DropHandler() {
- public AcceptCriterion getAcceptCriterion() {
- return AcceptAll.get();
- }
-
- public void drop(DragAndDropEvent event) {
- // Wrapper for the object that is dragged
- Transferable t = event.getTransferable();
-
- // Make sure the drag source is the same tree
- if (t.getSourceComponent() != tree)
- return;
-
- TreeTargetDetails target = (TreeTargetDetails)
- event.getTargetDetails();
-
- // Get ids of the dragged item and the target item
- Object sourceItemId = t.getData("itemId");
- Object targetItemId = target.getItemIdOver();
-
- // On which side of the target the item was dropped
- VerticalDropLocation location = target.getDropLocation();
-
- HierarchicalContainer container = (HierarchicalContainer)
- tree.getContainerDataSource();
-
- // Drop right on an item -> make it a child
- if (location == VerticalDropLocation.MIDDLE)
- tree.setParent(sourceItemId, targetItemId);
-
- // Drop at the top of a subtree -> make it previous
- else if (location == VerticalDropLocation.TOP) {
- Object parentId = container.getParent(targetItemId);
- container.setParent(sourceItemId, parentId);
- container.moveAfterSibling(sourceItemId, targetItemId);
- container.moveAfterSibling(targetItemId, sourceItemId);
- }
-
- // Drop below another item -> make it next
- else if (location == VerticalDropLocation.BOTTOM) {
- Object parentId = container.getParent(targetItemId);
- container.setParent(sourceItemId, parentId);
- container.moveAfterSibling(sourceItemId, targetItemId);
- }
- }
-});
-----
-
-[[advanced.dragndrop.treedrop.criteria]]
-=== Accept Criteria for Trees
-
-[classname]#Tree# defines some specialized accept criteria for trees.
-
-[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.
-[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:
-+
-[source, java]
-----
-return new Or (Tree.TargetItemAllowsChildren.get(), new Not(VerticalLocationIs.MIDDLE));
-----
-
-[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.
-
-
-In addition, the accept criteria defined in [classname]#AbstractSelect# are
-available for a [classname]#Tree#, as listed in
-<<advanced.dragndrop.acceptcriteria>>.
-
-
-
-[[advanced.dragndrop.tabledrop]]
-== Dropping Items On a [classname]#Table#
-
-You can drag items from, to, or within a [classname]#Table#. Making table a drag
-source requires simply setting the drag mode with [methodname]#setDragMode()#.
-[classname]#Table# supports dragging both single rows, with
-[literal]#++TableDragMode.ROW++#, and multiple rows, with
-[literal]#++TableDragMode.MULTIROW++#. While dragging, the dragged node or nodes
-are referenced with a [classname]#TreeTransferable# object, which is a
-[classname]#DataBoundTransferable#. Tree nodes are identified by the item IDs of
-the container items.
-
-When a transferable is dropped on a table, the drop location is stored in a
-[classname]#AbstractSelectTargetDetails# object, which identifies the target row
-by its item ID. You can get the item ID with [methodname]#getItemIdOver()#
-method. A drop can occur directly on or above or below a row; the exact location
-is a [classname]#VerticalDropLocation#, which you can get with the
-[methodname]#getDropLocation()# method from the details object.
-
-[[advanced.dragndrop.tabledrop.criteria]]
-=== Accept Criteria for Tables
-
-[classname]#Table# defines one specialized accept criterion for tables.
-
-[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.
-
-
-
-
-[[advanced.dragndrop.acceptcriteria]]
-== Accepting Drops
-
-((("Drag and Drop", "Accept Criteria", id="term.advanced.dragndrop.acceptcriteria", range="startofrange")))
-
-
-You can not drop the objects you are dragging around just anywhere. Before a
-drop is possible, the specific drop location on which the mouse hovers must be
-__accepted__. Hovering a dragged object over an accepted location displays an
-__accept indicator__, which allows the user to position the drop properly. As
-such checks have to be done all the time when the mouse pointer moves around the
-drop targets, it is not feasible to send the accept requests to the server-side,
-so drops on a target are normally accepted by a client-side __accept
-criterion__.
-
-A drop handler must define the criterion on the objects which it accepts to be
-dropped on the target. The criterion needs to be provided in the
-[classname]#getAcceptCriterion()# method of the [classname]#DropHandler#
-interface. A criterion is represented in an [classname]#AcceptCriterion# object,
-which can be a composite of multiple criteria that are evaluated using logical
-operations. There are two basic types of criteria: __client-side__ and
-__server-side criteria__. The various built-in criteria allow accepting drops
-based on the identity of the source and target components, and on the __data
-flavor__ of the dragged objects.
-
-To allow dropping any transferable objects, you can return a universal accept
-criterion, which you can get with [methodname]#AcceptAll.get()#.
-
-
-[source, java]
-----
-tree.setDropHandler(new DropHandler() {
- public AcceptCriterion getAcceptCriterion() {
- return AcceptAll.get();
- }
- ...
-----
-
-[[advanced.dragndrop.acceptcriteria.client-side]]
-=== Client-Side Criteria
-
-The __client-side criteria__, which inherit the
-[classname]#ClientSideCriterion#, are verified on the client-side, so server
-requests are not needed for verifying whether each component on which the mouse
-pointer hovers would accept a certain object.
-
-The following client-side criteria are define in
-[package]#com.vaadin.event.dd.acceptcriterion#:
-
-[classname]#AcceptAll#:: Accepts all transferables and targets.
-[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.
-[classname]#ContainsDataFlavour#:: The transferable must contain the defined data flavour.
-[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.
-[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.
-[classname]#SourceIs#:: Accepts all transferables from any of the given source components
-[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.
-[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.
-
-
-In addition, target components such as [classname]#Tree# and [classname]#Table#
-define some component-specific client-side accept criteria. See
-<<advanced.dragndrop.treedrop>> for more details.
-
-[classname]#AbstractSelect# defines the following criteria for all selection
-components, including [classname]#Tree# and [classname]#Table#.
-
-[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.
-[classname]#AcceptItem.ALL#:: Accepts all transferables as long as they are items.
-[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.
-[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:
-[source, java]
-----
-public AcceptCriterion getAcceptCriterion() {
- return new Not(VerticalLocationIs.MIDDLE);
-}
-----
-
-
-
-
-
-[[advanced.dragndrop.acceptcriteria.server-side]]
-=== Server-Side Criteria
-
-The __server-side criteria__ are verified on the server-side with the
-[methodname]#accept()# method of the [classname]#ServerSideCriterion# class.
-This allows fully programmable logic for accepting drops, but the negative side
-is that it causes a very large amount of server requests. A request is made for
-every target position on which the pointer hovers. This problem is eased in many
-cases by the component-specific lazy loading criteria
-[classname]#TableDropCriterion# and [classname]#TreeDropCriterion#. They do the
-server visit once for each drag and drop operation and return all accepted rows
-or nodes for current [classname]#Transferable# at once.
-
-The [methodname]#accept()# method gets the drag event as a parameter so it can
-perform its logic much like in [methodname]#drop()#.
-
-
-[source, java]
-----
-public AcceptCriterion getAcceptCriterion() {
- // Server-side accept criterion that allows drops on any other
- // location except on nodes that may not have children
- ServerSideCriterion criterion = new ServerSideCriterion() {
- public boolean accept(DragAndDropEvent dragEvent) {
- TreeTargetDetails target = (TreeTargetDetails)
- dragEvent.getTargetDetails();
-
- // The tree item on which the load hovers
- Object targetItemId = target.getItemIdOver();
-
- // On which side of the target the item is hovered
- VerticalDropLocation location = target.getDropLocation();
- if (location == VerticalDropLocation.MIDDLE)
- if (! tree.areChildrenAllowed(targetItemId))
- return false; // Not accepted
-
- return true; // Accept everything else
- }
- };
- return criterion;
-}
-----
-
-The server-side criteria base class [classname]#ServerSideCriterion# provides a
-generic [methodname]#accept()# method. The more specific
-[classname]#TableDropCriterion# and [classname]#TreeDropCriterion# are
-conveniency extensions that allow definiting allowed drop targets as a set of
-items. They also provide some optimization by lazy loading, which reduces server
-communications significantly.
-
-
-[source, java]
-----
-public AcceptCriterion getAcceptCriterion() {
- // Server-side accept criterion that allows drops on any
- // other tree node except on node that may not have children
- TreeDropCriterion criterion = new TreeDropCriterion() {
- @Override
- protected Set<Object> getAllowedItemIds(
- DragAndDropEvent dragEvent, Tree tree) {
- HashSet<Object> allowed = new HashSet<Object>();
- for (Iterator<Object> i =
- tree.getItemIds().iterator(); i.hasNext();) {
- Object itemId = i.next();
- if (tree.hasChildren(itemId))
- allowed.add(itemId);
- }
- return allowed;
- }
- };
- return criterion;
-}
-----
-
-
-[[advanced.dragndrop.acceptcriteria.indicators]]
-=== Accept Indicators
-
-When a dragged object hovers on a drop target, an __accept indicator__ is
-displayed to show whether or not the location is accepted. For
-[parameter]#MIDDLE# location, the indicator is a box around the target (tree
-node, table row, or component). For vertical drop locations, the accepted
-locations are shown as horizontal lines, and for horizontal drop locations as
-vertical lines.
-
-For [classname]#DragAndDropWrapper# drop targets, you can disable the accept
-indicators or __drag hints__ with the [parameter]#no-vertical-drag-hints#,
-[parameter]#no-horizontal-drag-hints#, and [parameter]#no-box-drag-hints#
-styles. You need to add the styles to the __layout that contains__ the wrapper,
-not to the wrapper itself.
-
-
-[source, java]
-----
-// Have a wrapper
-DragAndDropWrapper wrapper = new DragAndDropWrapper(c);
-layout.addComponent(wrapper);
-
-// Disable the hints
-layout.addStyleName("no-vertical-drag-hints");
-layout.addStyleName("no-horizontal-drag-hints");
-layout.addStyleName("no-box-drag-hints");
-----
-
-
-(((range="endofrange", startref="term.advanced.dragndrop.acceptcriteria")))
-
-[[advanced.dragndrop.dragging]]
-== Dragging Components
-
-Dragging a component requires wrapping the source component within a
-[classname]#DragAndDropWrapper#. You can then allow dragging by putting the
-wrapper (and the component) in drag mode with [methodname]#setDragStartMode()#.
-The method supports two drag modes: [parameter]#DragStartMode.WRAPPER# and
-[parameter]#DragStartMode.COMPONENT#, which defines whether the entire wrapper
-is shown as the drag image while dragging or just the wrapped component.
-
-
-[source, java]
-----
-// Have a component to drag
-final Button button = new Button("An Absolute Button");
-
-// Put the component in a D&D wrapper and allow dragging it
-final DragAndDropWrapper buttonWrap = new DragAndDropWrapper(button);
-buttonWrap.setDragStartMode(DragStartMode.COMPONENT);
-
-// Set the wrapper to wrap tightly around the component
-buttonWrap.setSizeUndefined();
-
-// Add the wrapper, not the component, to the layout
-layout.addComponent(buttonWrap, "left: 50px; top: 50px;");
-----
-
-The default height of [classname]#DragAndDropWrapper# is undefined, but the
-default width is 100%. If you want to ensure that the wrapper fits tightly
-around the wrapped component, you should call [methodname]#setSizeUndefined()#
-for the wrapper. Doing so, you should make sure that the wrapped component does
-not have a relative size, which would cause a paradox.
-
-Dragged components are referenced in the [classname]#WrapperTransferable#. You
-can get the reference to the dragged component with
-[methodname]#getDraggedComponent()#. The method will return [literal]#++null++#
-if the transferable is not a component. Also HTML 5 drags (see later) are held
-in wrapper transferables.
-
-
-[[advanced.dragndrop.drop-on-component]]
-== Dropping on a Component
-
-Drops on a component are enabled by wrapping the component in a
-[classname]#DragAndDropWrapper#. The wrapper is an ordinary component; the
-constructor takes the wrapped component as a parameter. You just need to define
-the [classname]#DropHandler# for the wrapper with
-[methodname]#setDropHandler()#.
-
-In the following example, we allow moving components in an absolute layout.
-Details on the drop handler are given later.
-
-
-[source, java]
-----
-// A layout that allows moving its contained components
-// by dragging and dropping them
-final AbsoluteLayout absLayout = new AbsoluteLayout();
-absLayout.setWidth("100%");
-absLayout.setHeight("400px");
-
-... put some (wrapped) components in the layout ...
-
-// Wrap the layout to allow handling drops
-DragAndDropWrapper layoutWrapper =
- new DragAndDropWrapper(absLayout);
-
-// Handle moving components within the AbsoluteLayout
-layoutWrapper.setDropHandler(new DropHandler() {
- public AcceptCriterion getAcceptCriterion() {
- return AcceptAll.get();
- }
-
- public void drop(DragAndDropEvent event) {
- ...
- }
-});
-----
-
-[[advanced.dragndrop.drop-on-component.details]]
-=== Target Details for Wrapped Components
-
-The drop handler receives the drop target details in a
-[classname]#WrapperTargetDetails# object, which implements the
-[classname]#TargetDetails# interface.
-
-
-[source, java]
-----
-public void drop(DragAndDropEvent event) {
- WrapperTransferable t =
- (WrapperTransferable) event.getTransferable();
- WrapperTargetDetails details =
- (WrapperTargetDetails) event.getTargetDetails();
-----
-
-The wrapper target details include a [classname]#MouseEventDetails# object,
-which you can get with [methodname]#getMouseEvent()#. You can use it to get the
-mouse coordinates for the position where the mouse button was released and the
-drag ended. Similarly, you can find out the drag start position from the
-transferable object (if it is a [classname]#WrapperTransferable#) with
-[methodname]#getMouseDownEvent()#.
-
-
-[source, java]
-----
-// Calculate the drag coordinate difference
-int xChange = details.getMouseEvent().getClientX()
- - t.getMouseDownEvent().getClientX();
-int yChange = details.getMouseEvent().getClientY()
- - t.getMouseDownEvent().getClientY();
-
-// Move the component in the absolute layout
-ComponentPosition pos =
- absLayout.getPosition(t.getSourceComponent());
-pos.setLeftValue(pos.getLeftValue() + xChange);
-pos.setTopValue(pos.getTopValue() + yChange);
-----
-
-You can get the absolute x and y coordinates of the target wrapper with
-[methodname]#getAbsoluteLeft()# and [methodname]#getAbsoluteTop()#, which allows
-you to translate the absolute mouse coordinates to coordinates relative to the
-wrapper. Notice that the coordinates are really the position of the wrapper, not
-the wrapped component; the wrapper reserves some space for the accept
-indicators.
-
-The [methodname]#verticalDropLocation()# and
-[methodname]#horizontalDropLocation()# return the more detailed drop location in
-the target.
-
-
-
-[[advanced.dragndrop.external]]
-== Dragging Files from Outside the Browser
-
-The [classname]#DragAndDropWrapper# allows dragging files from outside the
-browser and dropping them on a component wrapped in the wrapper. Dropped files
-are automatically uploaded to the application and can be acquired from the
-wrapper with [methodname]#getFiles()#. The files are represented as
-[classname]#Html5File# objects as defined in the inner class. You can define an
-upload [classname]#Receiver# to receive the content of a file to an
-[classname]#OutputStream#.
-
-Dragging and dropping files to browser is supported in HTML 5 and requires a
-compatible browser, such as Mozilla Firefox 3.6 or newer.
-
-
-(((range="endofrange", startref="term.advanced.dragndrop")))
-
-