CONTENTS | PREV | NEXT Drag and Drop

2.3 Drag Source

The DragSource is the entity responsible for the initiation of the Drag and Drop operation:

2.3.1 The DragSource definition

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 final 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 | 		                                             
	public static int ACTION_REFERENCE = 0x40000000;

public class java.awt.dnd.DragSource {

     public static Cursor     DefaultCopyDrop;
     public static Cursor     DefaultMoveDrop;
     public static Cursor     DefaultLinkDrop;

     public static Cursor     DefaultCopyNoDrop;
     public static Cursor     DefaultMoveNoDrop;
     public static Cursor     DefaultLinkNoDrop;

	public static DragSource getDefaultDragSource();

	public static boolean isDragImageSupported();

	public void
		  startDrag(DragGestureEvent    trigger,
				  Cursor			 dragCursor,
				  Image			 dragImage,
				  Point			 dragImageOffset,
				  Transferable 			 transferable,
			 	  DragSourceListener			 dsl,
			       FlavorMap           fm)
		  throws InvalidDnDOperationException;

	protected DragSourceContext
			DragSourceContextPeer dscp,
			DragGestureEvent      trigger,
			Cursor                dragCursor,
			Image                 dragImage,
  			Point                 dragImageOffset,
			Transferable          transferable,
			DragSourceListener    dsl

	public FlavorMap getFlavorMap();

     public DragGestureRecongizer
              Class               abstractRecognizerClass,
              Component           c,
              int                 srcActions,
              DragGestureListener dgl

     public DragGestureRecongizer
              Component           c,
              int                 srcActions,
              DragGestureListener dgl

The DragSource may be used in a number of scenarios:

A controlling object, shall obtain a DragSource instance prior to a users gesture, effecting an associated Component, in order to process the operation. Once obtained a DragGestureRecognizer should be obtained and used to associate the DragSource with a Component.

The initial interpretation of the users gesture, and the subsequent starting of the Drag operation are the responsibility of the implementing Component, this is usually implemented by a DragGestureRecognizer.

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. A DragSource shall only permit a single Drag and Drop operation to be current at any one time, and shall reject any further startDrag() requests by throwing an IllegalDnDOperationException until such time as the extant operation is complete.

In order to start a drag operation the caller of the startDrag() method shall provide the following parameters:

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. The presence of the facility on a particular platform may be tested by invoking the static method isDragImageSupported().

The Transferable instance associated with the DragSource at the start of the Drag operation, represents 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 with that.

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 exposed at the start of the Drag operation may change for the duration of the operation, in other words the operation(s) and are constant for the duration of the operation with respect to the DragSource.

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]

A "private" FlavorMap may be provided to the startDrag() method of the DragSource, or null, in which case the "default" FlavorMap for that DragSource class or instance is used.

2.3.2 The DragSourceContext Definition

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(
				DragSourceContextPeer	dscp,
				DragGestureEvent      trigger,
				Cursor			dragCursor,
				Image			dragImage,
				Point			dragOffset,
				Transferable		transferable,
				DragSourceListener		dsl		

	public DragSource			 getDragSource();

	public Component		 getComponent();

	public DragGestureEvent				getTrigger();

	public Image	 getDragImage();
	public Point	 getDragImageOffset();

     public void transferablesFlavorsChanged();

	public int getSourceActions();

	public Cursor getCursor();
	pbulic void   setCursor(Cursor Cursor) 
				   throws InvalidDnDOperationException;

	public void 
		addDragSourceListener(DragSourceListener dsl)
		    throws TooManyListenersException;

	public void 
		removeDragSourceListener(DragSourceListener dsl);

     protected updateCurrentCursor(int dropOperation,
                                   int targetActions,
                                   int status

    // values for status parameter above.

    protected static final int DEFAULT = 0;
    protected static final int ENTER   = 1;
    protected static final int OVER    = 2;
    protected static final int CHANGED = 3;

    protected boolean cursorDirty;

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 Drag operation has 2 logical cursor states (Drag Cursors) associated with it:

The state of the Cursor may be modified by calling the setCursor() method of the DragSourceContext.

2.3.3 The DragSourceListener Definition

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 dropActionChanged (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 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 DragSourceListener's dragExit() method is invoked when one of the following conditions is true:



The DragSourceListener's dropActionChanged() 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 getDropSuccess() method 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 current DragSourceContext and the associated resources are invalid.

2.3.4 The DragSourceEvent Definition

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.

2.3.5 The DragSourceDragEvent Definition

The DragSourceDragEvent class is defined as follows:

public class java.awt.dnd.DragSourceDragEvent 
	  extends DragSourceEvent {
	public int getTargetActions();

     public int getUserAction();

	public int getGestureModifiers();

	public boolean isDropTargetLocal();

     public int getDropAction();

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 dropActionChanged()).

The getDropAction() method returns the action that is currently selected by the users gesture.

The getTargetActions() method returns the set of actions supported by the current DropTarget.

The logical OR of these two results defines the actual effect of a Drop.

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.

2.3.6 The DragSourceDropEvent Definition

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 getDropSuccess();

	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 available to the initiator via the getDropSuccess() 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 outside a DropTarget, or if the DropTarget invokes rejectDrop(), the isGetDropSuccess() method will return false, otherwise true.

Copyright © 1997, 1998 Sun Microsystems, Inc. All Rights Reserved.