CONTENTS | PREV | NEXT | Drag and Drop |
The DragSource is the entity responsible for the initiation of the Drag and Drop operation:
The DragSource and associated constant interfaces are defined as follows:The DnDConstants class defines the operations that may be applied to the subject of the transfer:
public class java.awt.dnd.DnDConstants { public static int ACTION_NONE = 0x0; public static int ACTION_COPY = 0x1; public static int ACTION_MOVE = 0x2; public static int ACTION_COPY_OR_MOVE = ACTION_COPY | ACTION_MOVE; public static int ACTION_REFERENCE = 0x40000000; } public class java.awt.dnd.DragSource { public static Cursor getDefaultCopyDropCursor(); public static Cursor getDefaultMoveDropCursor(); public static Cursor getDefaultLinkDropCursor(); public static Cursor getDefaultCopyNoDropCursor(); public static Cursor getDefaultMoveNoDropCursor(); public static Cursor getDefaultLinkNoDropCursor(); public static DragSource getDefaultDragSource(); public void startDrag(Component c, AWTEvent trigger, int actions, Cursor dragCursor, Image dragImage, Point dragImageOffset, Transferable transferable, DragSourceListener dsl) throws InvalidDnDOperationException; protected DragSourceContext createDragSourceContext( DragSourceContextPeer dscp, Component c, int actions, Cursor dragCursor, Image dragImage, Point dragImageOffset, Transferable transferable, DragSourceListener dsl ); public FlavorMap getFlavorMap(); }
The DragSource may be used in a number of scenarios:
- 1 default instance per JVM for the lifetime of that JVM. (defined by this spec)
- 1 instance per class of potential Drag Initiator object (e.g TextField). [implementation dependent]
- 1 per instance of a particular Component, or application specific object associated with a Component instance in the GUI. [Implementation dependent]
- some other arbitrary association. [implementation dependent]
A controlling object, the Drag Initiator, shall obtain a DragSource instance either prior to, or at the time a users gesture, effecting an associated Component, in order to process the operation.The initial interpretation of the users gesture, and the subsequent starting of the Drag operation are the responsibility of the implementing Component, or associated controlling entity.
When a gesture occurs, the DragSource's startDrag() method shall be invoked in order to cause processing of the users navigational gestures and delivery of Drag and Drop protocol notifications.
In order to start a drag operation the caller of the startDrag() method shall provide the following parameters:
- The Component that received the AWTEvent that was interpreted as the starting gesture.
- The AWTEvent itself that was interpreted as the starting gesture.
- The Drop actions that may be performed; the union of ACTION_COPY, ACTION_MOVE, and ACTION_REFERENCE, as appropriate.
- A Cursor representing the initial "Drag Over" feedback for the operation(s) specified. (This shall be a Cursor that provides "No Drop" visual feedback to the user).
- An (optional) Image to visually represent the item, or item(s) that are the subject(s) of the operation.
On platforms that can support this feature, a "Drag" image may be associated with the operation to enhance the fidelity of the "Drag Over" feedback. This image would typically be a small "iconic" representation of the object, or objects being dragged, and would be rendered by the underlying system, tracking the movement of, and coincident with, but typically in addition to the Cursor animation.Where this facility is not available, or where the image is not of a suitable type to be rendered by the underlying system, this parameter is ignored and only Cursor "Drag Over" animation results, so applications should not depend upon this feature.
- Where an Image is provided; a Point (in the co-ordinate space of the Component) specifying the initial origin of that Image in the Component for the purposes of initiating "Drag Over" animation of that Image.
- A Transferable that describes the various DataFlavor(s) that represent the subject(s) of any subsequent data transfer that may result from a successful Drop.
The Transferable instance associated with the DragSource at the start of the Drag operation, represent the object(s) or data that are the operand(s), or the subject(s), of the Drag and Drop operation, that is the information that will subsequently be passed from the DragSource to the DropTarget as a result of a successful Drop on the Component associated with that DropTarget.Note that multiple (collections) of either homogeneous, or heterogeneous, objects may be subject of a Drag and Drop operation, by creating a container object, that is the subject of the transfer, and implements Transferable. However it should be noted that since none of the targeted native platforms systems support a standard mechanism for describing and thus transferring such collections it is not possible to implement such transfers in a transparent, or platform portable fashion.
As stated above, the primary role of the startDrag() method is to initiate a Drag on behalf of the user. In order to accomplish this, the startDrag() method must create a DragSourceContext instance to track the operation itself, and more importantly it must initiate the operation itself in the underlying platform implementation. In order to accomplish this, the DragSource must first obtain a DragSourceContextPeer from the underlying system (usually via an invocation of java.awt.Toolkit.createDragSourceContextPeer() method) and subsequently associate this newly created DragSourceContextPeer (which provides a platform independent interface to the underlying systems capabilities) with a DragSourceContext.The startDrag() method invokes the createDragSourceContext() method to instantiate an appropriate DragSourceContext and associate the DragSourceContextPeer.If the Drag and Drop System is unable to initiate a Drag operation for some reason the startDrag() method shall throw a java.awt.dnd.InvalidDnDOperationException to signal such a condition. Typically this exception is thrown when the underlying platform system is either not in a state to initiate a Drag, or the parameters specified are invalid.
Note that during the Drag neither the set of operations the source, nor the set of DataFlavors exposed by the Transferable at the start of the Drag operation may change for the duration of the operation, in other words the operation(s) and data are constant for the duration of the operation with respect to the DragSource.
For security reasons the caller of the startDrag() method is required to have the AWTPermission "startDrag", invoking this method without such permission shall result in a SecurityException being thrown.
The getFlavorMap() method is used by the underlying system to obtain a FlavorMap object in order to map the DataFlavors exposed by the Transferable to data type names of the underlying DnD platform. [see later for details of the FlavorMap]
As a result of a DragSource's startDrag() method being successfully invoked an instance of the DragSourceContext class is created. This instance is responsible for tracking the state of the operation on behalf of the DragSource and dispatching state changes to the DragSourceListener.The DragSourceContext class is defined as follows:
public class DragSourceContext implements DragSourceListener { protected DragSourceContext( DragSource ds, DragSourceContextPeer dscp, int actions, Cursor dragCursor, Image dragImage, Point dragOffset, Transferable transferable, DragSourceListener dsl ); public DragSource getDragSource(); public Component getComponent(); public AWTEvent getTrigger(); public Image getDragImage(); public Point getDragImageOffset(); public int getSourceActions(); Cursor getCursor(); void setCursor(Cursor Cursor) throws InvalidDnDOperationException; void cancelDrag() throws InvalidDnDOperationException; void addDragSourceListener(DragSourceListener dsl) throws TooManyListenersException; void removeDragSourceListener(DragSourceListener dsl); }
Note that the DragSourceContext itself implements DragSourceListener, this is to allow the platform peer, the DragSourceContextPeer instance, created by the DragSource, to notify the DragSourceContext of changes in state in the ongoing operation, and thus allows the DragSourceContext to interpose itself between the platform and the DragSourceListener provided by the initiator of the operation.The state machine the platform exposes, with respect to the source, or initiator of the Drag and Drop operation is detailed below:
Notifications of changes in state with respect to the initiator during a Drag and Drop operation, as illustrated above, are delivered from the DragSourceContextPeer, to the appropriate DragSourceContext, which delegates notifications, via a unicast JavaBeans compliant EventListener subinterface, to an arbitrary object that implements DragSourceListener registered with the DragSource via startDrag().
The primary responsibility of the DragSourceListener is to monitor the progress of the users navigation during the Drag and Drop operation and provide the "Drag-Over" effects feedback to the user. Typically this is accomplished via changes to the "Drag Cursor".
Every DragSource object has 2 logical cursor states associated with it:
The state of the Cursor may be modified by calling the setCursor() method of the DragSourceContext.
The DragSourceListener interface is defined as follows:
public interface java.awt.dnd.DragSourceListener extends java.util.EventListener { void dragEnter (DragSourceDragEvent dsde); void dragOver (DragSourceDragEvent dsde); void dragGestureChanged(DragSourceDragEvent dsde); void dragExit (DragSourceEvent dse); void dragDropEnd (DragSourceDropEvent dsde); }
As the drag operation progresses, the DragSourceListener's dragEnter(), dragOver(), and dragExit() methods shall be invoked as a result of the users navigation of the logical "Drag" cursor's location intersecting the geometry of GUI Component(s) with associated DropTarget(s). [See below for details of the DropTarget's protocol interactions].The DragSourceListener's dragEnter() method is invoked when the following conditions are true:
- The logical cursor's hotspot initially intersects a GUI Component's visible geometry.
- That Component has an active DropTarget associated.
- The DropTarget's registered DropTargetListener dragEnter() method is invoked and returns successfully.
- The registered DropTargetListener invokes the DropTargetDragEvent's acceptDrag() method to accept the Drag based upon interrogation of the source's potential Drop actions and available data types (DataFlavors).
The DragSourceListener's dragOver() method is invoked when the following conditions are true:
- The cursor's logical hotspot has moved but still intersects the visible geometry of the Component associated with the previous dragEnter() invocation.
- That Component still has a DropTarget associated.
- That DropTarget is still active.
- The DropTarget's registered DropTargetListener dragOver() method is invoked and returns successfully.
- The DropTarget does not reject the drag via rejectDrag().
The DragSourceListener's dragExit() method is invoked when one of the following conditions is true:
Or:
Or:
The DragSourceListener's dragGestureChanged() method is invoked when the state of the input device(s), typically the mouse buttons or keyboard modifiers, that the user is interacting with in order to preform the Drag operation, changes.The dragDropEnd() method is invoked to signify that the operation is completed. The isDropAborted() and isDropSuccessful() methods of the DragSourceDropEvent can be used to determine the termination state. The getDropAction() method returns the operation that the DropTarget selected (via the DropTargetDropEvent acceptDrop() parameter) to apply to the Drop operation.1
Once this method is complete the DragSourceContext and the associated resources are invalid.
The DragSourceEvent class is the root Event class for all events pertaining to the DragSource, and is defined as follows:
public class java.awt.dnd.DragSourceEvent extends java.util.EventObject { public DragSourceEvent(DragSourceContext dsc); public DragSourceContext getDragSourceContext(); };
An instance of this event is passed to the DragSourceListener dragExit() method.
The DragSourceDragEvent class is defined as follows:
public class java.awt.dnd.DragSourceDragEvent extends DragSourceEvent { public int getTargetActions(); public int getGestureModifiers(); public boolean isDropTargetLocal(); }
An instance of the above class is passed to a DragSourceListener's dragEnter(), dragOver(), and dragGestureChanged() methods.The getDragSourceContext() method returns the DragSourceContext associated with the current Drag and Drop operation.
The getTargetActions() method returns the drop actions, supported by, and returned from the current DropTarget (if any in the case of dragGestureChanged()).
The getGestureModifiers() returns the current state of the input device modifiers, usually the mouse buttons and keyboard modifiers, associated with the users gesture.
The isDropTargetLocal() method returns true if the current DropTarget is contained within the same JVM as the DragSource, and false otherwise. This information can be useful to the implementor of the DragSource's Transferable in order to implement certain local optimizations.
The DragSourceDropEvent class is defined as follows:
public public class java.awt.dnd.DragSourceDropEvent extends java.util.EventObject { public DragSourceDropEvent(DragSourceContext dsc); public DragSourceDropEvent(DragSourceContext dsc, int action, boolean success); public boolean isDropAborted(); public boolean isDropSuccessful(); public int getDropAction(); }
An instance of the above class is passed to a DragSourceListener's dragDropEnd() method. This event encapsulates the termination state of the Drag and Drop operation for the DragSource.If the Drop occurs, then the participating DropTarget will signal the success or failure of the data transfer via the DropTargetContext's dropComplete() method, this status is made availlable to the initiator via the isDropSuccessful() method. The operation that the destination DropTarget selected to perform on the subject of the Drag (passed by the DropTarget's acceptDrop() method) is returned via the getDropAction() method.
If the Drag operation was aborted for any reason prior to a Drop occurring, for example if the users ends the gesture outwith a DropTarget, or if the DropTarget invokes rejectDrop() , the isDropAborted() method will return false, otherwise true.