< prev index next >

src/java.desktop/share/classes/java/awt/dnd/DragSourceContext.java

Print this page




  29 import java.awt.Component;
  30 import java.awt.Cursor;
  31 import java.awt.Image;
  32 import java.awt.Point;
  33 import java.awt.Toolkit;
  34 import java.awt.datatransfer.DataFlavor;
  35 import java.awt.datatransfer.Transferable;
  36 import java.awt.datatransfer.UnsupportedFlavorException;
  37 import java.awt.dnd.peer.DragSourceContextPeer;
  38 import java.io.IOException;
  39 import java.io.InvalidObjectException;
  40 import java.io.ObjectInputStream;
  41 import java.io.ObjectOutputStream;
  42 import java.io.Serializable;
  43 import java.util.TooManyListenersException;
  44 
  45 import sun.awt.AWTAccessor;
  46 import sun.awt.ComponentFactory;
  47 
  48 /**
  49  * The <code>DragSourceContext</code> class is responsible for managing the
  50  * initiator side of the Drag and Drop protocol. In particular, it is responsible
  51  * for managing drag event notifications to the
  52  * {@linkplain DragSourceListener DragSourceListeners}
  53  * and {@linkplain DragSourceMotionListener DragSourceMotionListeners}, and providing the
  54  * {@link Transferable} representing the source data for the drag operation.
  55  * <p>
  56  * Note that the <code>DragSourceContext</code> itself
  57  * implements the <code>DragSourceListener</code> and
  58  * <code>DragSourceMotionListener</code> interfaces.
  59  * This is to allow the platform peer
  60  * (the {@link DragSourceContextPeer} instance)
  61  * created by the {@link DragSource} to notify
  62  * the <code>DragSourceContext</code> of
  63  * state changes in the ongoing operation. This allows the
  64  * <code>DragSourceContext</code> object to interpose
  65  * itself between the platform and the
  66  * listeners provided by the initiator of the drag operation.
  67  * <p>
  68  * <a name="defaultCursor"></a>
  69  * By default, {@code DragSourceContext} sets the cursor as appropriate
  70  * for the current state of the drag and drop operation. For example, if
  71  * the user has chosen {@linkplain DnDConstants#ACTION_MOVE the move action},
  72  * and the pointer is over a target that accepts
  73  * the move action, the default move cursor is shown. When
  74  * the pointer is over an area that does not accept the transfer,
  75  * the default "no drop" cursor is shown.
  76  * <p>
  77  * This default handling mechanism is disabled when a custom cursor is set
  78  * by the {@link #setCursor} method. When the default handling is disabled,
  79  * it becomes the responsibility
  80  * of the developer to keep the cursor up to date, by listening
  81  * to the {@code DragSource} events and calling the {@code setCursor()} method.
  82  * Alternatively, you can provide custom cursor behavior by providing
  83  * custom implementations of the {@code DragSource}
  84  * and the {@code DragSourceContext} classes.
  85  *
  86  * @see DragSourceListener
  87  * @see DragSourceMotionListener
  88  * @see DnDConstants
  89  * @since 1.2
  90  */
  91 
  92 public class DragSourceContext
  93     implements DragSourceListener, DragSourceMotionListener, Serializable {
  94 
  95     private static final long serialVersionUID = -115407898692194719L;
  96 
  97     // used by updateCurrentCursor
  98 
  99     /**
 100      * An <code>int</code> used by updateCurrentCursor()
 101      * indicating that the <code>Cursor</code> should change
 102      * to the default (no drop) <code>Cursor</code>.
 103      */
 104     protected static final int DEFAULT = 0;
 105 
 106     /**
 107      * An <code>int</code> used by updateCurrentCursor()
 108      * indicating that the <code>Cursor</code>
 109      * has entered a <code>DropTarget</code>.
 110      */
 111     protected static final int ENTER   = 1;
 112 
 113     /**
 114      * An <code>int</code> used by updateCurrentCursor()
 115      * indicating that the <code>Cursor</code> is
 116      * over a <code>DropTarget</code>.
 117      */
 118     protected static final int OVER    = 2;
 119 
 120     /**
 121      * An <code>int</code> used by updateCurrentCursor()
 122      * indicating that the user operation has changed.
 123      */
 124 
 125     protected static final int CHANGED = 3;
 126 
 127     static {
 128         AWTAccessor.setDragSourceContextAccessor(dsc -> dsc.peer);
 129     }
 130 
 131     /**
 132      * Called from <code>DragSource</code>, this constructor creates a new
 133      * <code>DragSourceContext</code> given the
 134      * <code>DragSourceContextPeer</code> for this Drag, the
 135      * <code>DragGestureEvent</code> that triggered the Drag, the initial
 136      * <code>Cursor</code> to use for the Drag, an (optional)
 137      * <code>Image</code> to display while the Drag is taking place, the offset
 138      * of the <code>Image</code> origin from the hotspot at the instant of the
 139      * triggering event, the <code>Transferable</code> subject data, and the
 140      * <code>DragSourceListener</code> to use during the Drag and Drop
 141      * operation.
 142      * <br>
 143      * If <code>DragSourceContextPeer</code> is <code>null</code>
 144      * <code>NullPointerException</code> is thrown.
 145      * <br>
 146      * If <code>DragGestureEvent</code> is <code>null</code>
 147      * <code>NullPointerException</code> is thrown.
 148      * <br>
 149      * If <code>Cursor</code> is <code>null</code> no exception is thrown and
 150      * the default drag cursor behavior is activated for this drag operation.
 151      * <br>
 152      * If <code>Image</code> is <code>null</code> no exception is thrown.
 153      * <br>
 154      * If <code>Image</code> is not <code>null</code> and the offset is
 155      * <code>null</code> <code>NullPointerException</code> is thrown.
 156      * <br>
 157      * If <code>Transferable</code> is <code>null</code>
 158      * <code>NullPointerException</code> is thrown.
 159      * <br>
 160      * If <code>DragSourceListener</code> is <code>null</code> no exception
 161      * is thrown.
 162      *
 163      * @param trigger    the triggering event
 164      * @param dragCursor     the initial {@code Cursor} for this drag operation
 165      *                       or {@code null} for the default cursor handling;
 166      *                       see <a href="DragSourceContext.html#defaultCursor">class level documentation</a>
 167      *                       for more details on the cursor handling mechanism during drag and drop
 168      * @param dragImage  the <code>Image</code> to drag (or <code>null</code>)
 169      * @param offset     the offset of the image origin from the hotspot at the
 170      *                   instant of the triggering event
 171      * @param t          the <code>Transferable</code>
 172      * @param dsl        the <code>DragSourceListener</code>
 173      *
 174      * @throws IllegalArgumentException if the <code>Component</code> associated
 175      *         with the trigger event is <code>null</code>.
 176      * @throws IllegalArgumentException if the <code>DragSource</code> for the
 177      *         trigger event is <code>null</code>.
 178      * @throws IllegalArgumentException if the drag action for the
 179      *         trigger event is <code>DnDConstants.ACTION_NONE</code>.
 180      * @throws IllegalArgumentException if the source actions for the
 181      *         <code>DragGestureRecognizer</code> associated with the trigger
 182      *         event are equal to <code>DnDConstants.ACTION_NONE</code>.
 183      * @throws NullPointerException if dscp, trigger, or t are null, or
 184      *         if dragImage is non-null and offset is null
 185      */
 186     public DragSourceContext(DragGestureEvent trigger, Cursor dragCursor,
 187                              Image dragImage, Point offset, Transferable t,
 188                              DragSourceListener dsl) {
 189         Toolkit toolkit = Toolkit.getDefaultToolkit();
 190         if (!(toolkit instanceof ComponentFactory)) {
 191             throw new AWTError("Unsupported toolkit: " + toolkit);
 192         }
 193         DragSourceContextPeer dscp = ((ComponentFactory) toolkit).
 194                 createDragSourceContextPeer(trigger);
 195 
 196         if (dscp == null) {
 197             throw new NullPointerException("DragSourceContextPeer");
 198         }
 199 
 200         if (trigger == null) {
 201             throw new NullPointerException("Trigger");
 202         }


 223         }
 224 
 225         if (dragImage != null && offset == null) {
 226             throw new NullPointerException("offset");
 227         }
 228 
 229         peer         = dscp;
 230         this.trigger = trigger;
 231         cursor       = dragCursor;
 232         transferable = t;
 233         listener     = dsl;
 234         sourceActions =
 235             trigger.getSourceAsDragGestureRecognizer().getSourceActions();
 236 
 237         useCustomCursor = (dragCursor != null);
 238 
 239         updateCurrentCursor(trigger.getDragAction(), getSourceActions(), DEFAULT);
 240     }
 241 
 242     /**
 243      * Returns the <code>DragSource</code>
 244      * that instantiated this <code>DragSourceContext</code>.
 245      *
 246      * @return the <code>DragSource</code> that
 247      *   instantiated this <code>DragSourceContext</code>
 248      */
 249 
 250     public DragSource   getDragSource() { return trigger.getDragSource(); }
 251 
 252     /**
 253      * Returns the <code>Component</code> associated with this
 254      * <code>DragSourceContext</code>.
 255      *
 256      * @return the <code>Component</code> that started the drag
 257      */
 258 
 259     public Component    getComponent() { return trigger.getComponent(); }
 260 
 261     /**
 262      * Returns the <code>DragGestureEvent</code>
 263      * that initially triggered the drag.
 264      *
 265      * @return the Event that triggered the drag
 266      */
 267 
 268     public DragGestureEvent getTrigger() { return trigger; }
 269 
 270     /**
 271      * Returns a bitwise mask of <code>DnDConstants</code> that
 272      * represent the set of drop actions supported by the drag source for the
 273      * drag operation associated with this <code>DragSourceContext</code>.
 274      *
 275      * @return the drop actions supported by the drag source
 276      */
 277     public int  getSourceActions() {
 278         return sourceActions;
 279     }
 280 
 281     /**
 282      * Sets the cursor for this drag operation to the specified
 283      * <code>Cursor</code>.  If the specified <code>Cursor</code>
 284      * is <code>null</code>, the default drag cursor behavior is
 285      * activated for this drag operation, otherwise it is deactivated.
 286      *
 287      * @param c     the initial {@code Cursor} for this drag operation,
 288      *                       or {@code null} for the default cursor handling;
 289      *                       see {@linkplain Cursor class
 290      *                       level documentation} for more details
 291      *                       on the cursor handling during drag and drop
 292      *
 293      */
 294 
 295     public synchronized void setCursor(Cursor c) {
 296         useCustomCursor = (c != null);
 297         setCursorImpl(c);
 298     }
 299 
 300     /**
 301      * Returns the current drag <code>Cursor</code>.
 302      *
 303      * @return the current drag <code>Cursor</code>
 304      */
 305 
 306     public Cursor getCursor() { return cursor; }
 307 
 308     /**
 309      * Add a <code>DragSourceListener</code> to this
 310      * <code>DragSourceContext</code> if one has not already been added.
 311      * If a <code>DragSourceListener</code> already exists,
 312      * this method throws a <code>TooManyListenersException</code>.
 313      *
 314      * @param dsl the <code>DragSourceListener</code> to add.
 315      * Note that while <code>null</code> is not prohibited,
 316      * it is not acceptable as a parameter.
 317      *
 318      * @throws TooManyListenersException if
 319      * a <code>DragSourceListener</code> has already been added
 320      */
 321 
 322     public synchronized void addDragSourceListener(DragSourceListener dsl) throws TooManyListenersException {
 323         if (dsl == null) return;
 324 
 325         if (equals(dsl)) throw new IllegalArgumentException("DragSourceContext may not be its own listener");
 326 
 327         if (listener != null)
 328             throw new TooManyListenersException();
 329         else
 330             listener = dsl;
 331     }
 332 
 333     /**
 334      * Removes the specified <code>DragSourceListener</code>
 335      * from  this <code>DragSourceContext</code>.
 336      *
 337      * @param dsl the <code>DragSourceListener</code> to remove;
 338      *     note that while <code>null</code> is not prohibited,
 339      *     it is not acceptable as a parameter
 340      */
 341 
 342     public synchronized void removeDragSourceListener(DragSourceListener dsl) {
 343         if (listener != null && listener.equals(dsl)) {
 344             listener = null;
 345         } else
 346             throw new IllegalArgumentException();
 347     }
 348 
 349     /**
 350      * Notifies the peer that the <code>Transferable</code>'s
 351      * <code>DataFlavor</code>s have changed.
 352      */
 353 
 354     public void transferablesFlavorsChanged() {
 355         if (peer != null) peer.transferablesFlavorsChanged();
 356     }
 357 
 358     /**
 359      * Calls <code>dragEnter</code> on the
 360      * <code>DragSourceListener</code>s registered with this
 361      * <code>DragSourceContext</code> and with the associated
 362      * <code>DragSource</code>, and passes them the specified
 363      * <code>DragSourceDragEvent</code>.
 364      *
 365      * @param dsde the <code>DragSourceDragEvent</code>
 366      */
 367     public void dragEnter(DragSourceDragEvent dsde) {
 368         DragSourceListener dsl = listener;
 369         if (dsl != null) {
 370             dsl.dragEnter(dsde);
 371         }
 372         getDragSource().processDragEnter(dsde);
 373 
 374         updateCurrentCursor(getSourceActions(), dsde.getTargetActions(), ENTER);
 375     }
 376 
 377     /**
 378      * Calls <code>dragOver</code> on the
 379      * <code>DragSourceListener</code>s registered with this
 380      * <code>DragSourceContext</code> and with the associated
 381      * <code>DragSource</code>, and passes them the specified
 382      * <code>DragSourceDragEvent</code>.
 383      *
 384      * @param dsde the <code>DragSourceDragEvent</code>
 385      */
 386     public void dragOver(DragSourceDragEvent dsde) {
 387         DragSourceListener dsl = listener;
 388         if (dsl != null) {
 389             dsl.dragOver(dsde);
 390         }
 391         getDragSource().processDragOver(dsde);
 392 
 393         updateCurrentCursor(getSourceActions(), dsde.getTargetActions(), OVER);
 394     }
 395 
 396     /**
 397      * Calls <code>dragExit</code> on the
 398      * <code>DragSourceListener</code>s registered with this
 399      * <code>DragSourceContext</code> and with the associated
 400      * <code>DragSource</code>, and passes them the specified
 401      * <code>DragSourceEvent</code>.
 402      *
 403      * @param dse the <code>DragSourceEvent</code>
 404      */
 405     public void dragExit(DragSourceEvent dse) {
 406         DragSourceListener dsl = listener;
 407         if (dsl != null) {
 408             dsl.dragExit(dse);
 409         }
 410         getDragSource().processDragExit(dse);
 411 
 412         updateCurrentCursor(DnDConstants.ACTION_NONE, DnDConstants.ACTION_NONE, DEFAULT);
 413     }
 414 
 415     /**
 416      * Calls <code>dropActionChanged</code> on the
 417      * <code>DragSourceListener</code>s registered with this
 418      * <code>DragSourceContext</code> and with the associated
 419      * <code>DragSource</code>, and passes them the specified
 420      * <code>DragSourceDragEvent</code>.
 421      *
 422      * @param dsde the <code>DragSourceDragEvent</code>
 423      */
 424     public void dropActionChanged(DragSourceDragEvent dsde) {
 425         DragSourceListener dsl = listener;
 426         if (dsl != null) {
 427             dsl.dropActionChanged(dsde);
 428         }
 429         getDragSource().processDropActionChanged(dsde);
 430 
 431         updateCurrentCursor(getSourceActions(), dsde.getTargetActions(), CHANGED);
 432     }
 433 
 434     /**
 435      * Calls <code>dragDropEnd</code> on the
 436      * <code>DragSourceListener</code>s registered with this
 437      * <code>DragSourceContext</code> and with the associated
 438      * <code>DragSource</code>, and passes them the specified
 439      * <code>DragSourceDropEvent</code>.
 440      *
 441      * @param dsde the <code>DragSourceDropEvent</code>
 442      */
 443     public void dragDropEnd(DragSourceDropEvent dsde) {
 444         DragSourceListener dsl = listener;
 445         if (dsl != null) {
 446             dsl.dragDropEnd(dsde);
 447         }
 448         getDragSource().processDragDropEnd(dsde);
 449     }
 450 
 451     /**
 452      * Calls <code>dragMouseMoved</code> on the
 453      * <code>DragSourceMotionListener</code>s registered with the
 454      * <code>DragSource</code> associated with this
 455      * <code>DragSourceContext</code>, and them passes the specified
 456      * <code>DragSourceDragEvent</code>.
 457      *
 458      * @param dsde the <code>DragSourceDragEvent</code>
 459      * @since 1.4
 460      */
 461     public void dragMouseMoved(DragSourceDragEvent dsde) {
 462         getDragSource().processDragMouseMoved(dsde);
 463     }
 464 
 465     /**
 466      * Returns the <code>Transferable</code> associated with
 467      * this <code>DragSourceContext</code>.
 468      *
 469      * @return the <code>Transferable</code>
 470      */
 471     public Transferable getTransferable() { return transferable; }
 472 
 473     /**
 474      * If the default drag cursor behavior is active, this method
 475      * sets the default drag cursor for the specified actions
 476      * supported by the drag source, the drop target action,
 477      * and status, otherwise this method does nothing.
 478      *
 479      * @param sourceAct the actions supported by the drag source
 480      * @param targetAct the drop target action
 481      * @param status one of the fields <code>DEFAULT</code>,
 482      *               <code>ENTER</code>, <code>OVER</code>,
 483      *               <code>CHANGED</code>
 484      */
 485     @SuppressWarnings("fallthrough")
 486     protected synchronized void updateCurrentCursor(int sourceAct, int targetAct, int status) {
 487 
 488         // if the cursor has been previously set then don't do any defaults
 489         // processing.
 490 
 491         if (useCustomCursor) {
 492             return;
 493         }
 494 
 495         // do defaults processing
 496 
 497         Cursor c = null;
 498 
 499         switch (status) {
 500             default:
 501                 targetAct = DnDConstants.ACTION_NONE;
 502             case ENTER:
 503             case OVER:


 515                     if ((ra & DnDConstants.ACTION_LINK) == DnDConstants.ACTION_LINK)
 516                         c = DragSource.DefaultLinkDrop;
 517                     else if ((ra & DnDConstants.ACTION_MOVE) == DnDConstants.ACTION_MOVE)
 518                         c = DragSource.DefaultMoveDrop;
 519                     else
 520                         c = DragSource.DefaultCopyDrop;
 521                 }
 522         }
 523 
 524         setCursorImpl(c);
 525     }
 526 
 527     private void setCursorImpl(Cursor c) {
 528         if (cursor == null || !cursor.equals(c)) {
 529             cursor = c;
 530             if (peer != null) peer.setCursor(cursor);
 531         }
 532     }
 533 
 534     /**
 535      * Serializes this <code>DragSourceContext</code>. This method first
 536      * performs default serialization. Next, this object's
 537      * <code>Transferable</code> is written out if and only if it can be
 538      * serialized. If not, <code>null</code> is written instead. In this case,
 539      * a <code>DragSourceContext</code> created from the resulting deserialized
 540      * stream will contain a dummy <code>Transferable</code> which supports no
 541      * <code>DataFlavor</code>s. Finally, this object's
 542      * <code>DragSourceListener</code> is written out if and only if it can be
 543      * serialized. If not, <code>null</code> is written instead.
 544      *
 545      * @serialData The default serializable fields, in alphabetical order,
 546      *             followed by either a <code>Transferable</code> instance, or
 547      *             <code>null</code>, followed by either a
 548      *             <code>DragSourceListener</code> instance, or
 549      *             <code>null</code>.
 550      * @since 1.4
 551      */
 552     private void writeObject(ObjectOutputStream s) throws IOException {
 553         s.defaultWriteObject();
 554 
 555         s.writeObject(SerializationTester.test(transferable)
 556                       ? transferable : null);
 557         s.writeObject(SerializationTester.test(listener)
 558                       ? listener : null);
 559     }
 560 
 561     /**
 562      * Deserializes this <code>DragSourceContext</code>. This method first
 563      * performs default deserialization for all non-<code>transient</code>
 564      * fields. This object's <code>Transferable</code> and
 565      * <code>DragSourceListener</code> are then deserialized as well by using
 566      * the next two objects in the stream. If the resulting
 567      * <code>Transferable</code> is <code>null</code>, this object's
 568      * <code>Transferable</code> is set to a dummy <code>Transferable</code>
 569      * which supports no <code>DataFlavor</code>s.
 570      *
 571      * @since 1.4
 572      */
 573     private void readObject(ObjectInputStream s)
 574         throws ClassNotFoundException, IOException
 575     {
 576         ObjectInputStream.GetField f = s.readFields();
 577 
 578         DragGestureEvent newTrigger = (DragGestureEvent)f.get("trigger", null);
 579         if (newTrigger == null) {
 580             throw new InvalidObjectException("Null trigger");
 581         }
 582         if (newTrigger.getDragSource() == null) {
 583             throw new InvalidObjectException("Null DragSource");
 584         }
 585         if (newTrigger.getComponent() == null) {
 586             throw new InvalidObjectException("Null trigger component");
 587         }
 588 
 589         int newSourceActions = f.get("sourceActions", 0)


 637 
 638     /**
 639      * The event which triggered the start of the drag.
 640      *
 641      * @serial
 642      */
 643     private DragGestureEvent    trigger;
 644 
 645     /**
 646      * The current drag cursor.
 647      *
 648      * @serial
 649      */
 650     private Cursor              cursor;
 651 
 652     private transient Transferable      transferable;
 653 
 654     private transient DragSourceListener    listener;
 655 
 656     /**
 657      * <code>true</code> if the custom drag cursor is used instead of the
 658      * default one.
 659      *
 660      * @serial
 661      */
 662     private boolean useCustomCursor;
 663 
 664     /**
 665      * A bitwise mask of <code>DnDConstants</code> that represents the set of
 666      * drop actions supported by the drag source for the drag operation associated
 667      * with this <code>DragSourceContext.</code>
 668      *
 669      * @serial
 670      */
 671     private int sourceActions;
 672 }


  29 import java.awt.Component;
  30 import java.awt.Cursor;
  31 import java.awt.Image;
  32 import java.awt.Point;
  33 import java.awt.Toolkit;
  34 import java.awt.datatransfer.DataFlavor;
  35 import java.awt.datatransfer.Transferable;
  36 import java.awt.datatransfer.UnsupportedFlavorException;
  37 import java.awt.dnd.peer.DragSourceContextPeer;
  38 import java.io.IOException;
  39 import java.io.InvalidObjectException;
  40 import java.io.ObjectInputStream;
  41 import java.io.ObjectOutputStream;
  42 import java.io.Serializable;
  43 import java.util.TooManyListenersException;
  44 
  45 import sun.awt.AWTAccessor;
  46 import sun.awt.ComponentFactory;
  47 
  48 /**
  49  * The {@code DragSourceContext} class is responsible for managing the
  50  * initiator side of the Drag and Drop protocol. In particular, it is responsible
  51  * for managing drag event notifications to the
  52  * {@linkplain DragSourceListener DragSourceListeners}
  53  * and {@linkplain DragSourceMotionListener DragSourceMotionListeners}, and providing the
  54  * {@link Transferable} representing the source data for the drag operation.
  55  * <p>
  56  * Note that the {@code DragSourceContext} itself
  57  * implements the {@code DragSourceListener} and
  58  * {@code DragSourceMotionListener} interfaces.
  59  * This is to allow the platform peer
  60  * (the {@link DragSourceContextPeer} instance)
  61  * created by the {@link DragSource} to notify
  62  * the {@code DragSourceContext} of
  63  * state changes in the ongoing operation. This allows the
  64  * {@code DragSourceContext} object to interpose
  65  * itself between the platform and the
  66  * listeners provided by the initiator of the drag operation.
  67  * <p>
  68  * <a name="defaultCursor"></a>
  69  * By default, {@code DragSourceContext} sets the cursor as appropriate
  70  * for the current state of the drag and drop operation. For example, if
  71  * the user has chosen {@linkplain DnDConstants#ACTION_MOVE the move action},
  72  * and the pointer is over a target that accepts
  73  * the move action, the default move cursor is shown. When
  74  * the pointer is over an area that does not accept the transfer,
  75  * the default "no drop" cursor is shown.
  76  * <p>
  77  * This default handling mechanism is disabled when a custom cursor is set
  78  * by the {@link #setCursor} method. When the default handling is disabled,
  79  * it becomes the responsibility
  80  * of the developer to keep the cursor up to date, by listening
  81  * to the {@code DragSource} events and calling the {@code setCursor()} method.
  82  * Alternatively, you can provide custom cursor behavior by providing
  83  * custom implementations of the {@code DragSource}
  84  * and the {@code DragSourceContext} classes.
  85  *
  86  * @see DragSourceListener
  87  * @see DragSourceMotionListener
  88  * @see DnDConstants
  89  * @since 1.2
  90  */
  91 
  92 public class DragSourceContext
  93     implements DragSourceListener, DragSourceMotionListener, Serializable {
  94 
  95     private static final long serialVersionUID = -115407898692194719L;
  96 
  97     // used by updateCurrentCursor
  98 
  99     /**
 100      * An {@code int} used by updateCurrentCursor()
 101      * indicating that the {@code Cursor} should change
 102      * to the default (no drop) {@code Cursor}.
 103      */
 104     protected static final int DEFAULT = 0;
 105 
 106     /**
 107      * An {@code int} used by updateCurrentCursor()
 108      * indicating that the {@code Cursor}
 109      * has entered a {@code DropTarget}.
 110      */
 111     protected static final int ENTER   = 1;
 112 
 113     /**
 114      * An {@code int} used by updateCurrentCursor()
 115      * indicating that the {@code Cursor} is
 116      * over a {@code DropTarget}.
 117      */
 118     protected static final int OVER    = 2;
 119 
 120     /**
 121      * An {@code int} used by updateCurrentCursor()
 122      * indicating that the user operation has changed.
 123      */
 124 
 125     protected static final int CHANGED = 3;
 126 
 127     static {
 128         AWTAccessor.setDragSourceContextAccessor(dsc -> dsc.peer);
 129     }
 130 
 131     /**
 132      * Called from {@code DragSource}, this constructor creates a new
 133      * {@code DragSourceContext} given the
 134      * {@code DragSourceContextPeer} for this Drag, the
 135      * {@code DragGestureEvent} that triggered the Drag, the initial
 136      * {@code Cursor} to use for the Drag, an (optional)
 137      * {@code Image} to display while the Drag is taking place, the offset
 138      * of the {@code Image} origin from the hotspot at the instant of the
 139      * triggering event, the {@code Transferable} subject data, and the
 140      * {@code DragSourceListener} to use during the Drag and Drop
 141      * operation.
 142      * <br>
 143      * If {@code DragSourceContextPeer} is {@code null}
 144      * {@code NullPointerException} is thrown.
 145      * <br>
 146      * If {@code DragGestureEvent} is {@code null}
 147      * {@code NullPointerException} is thrown.
 148      * <br>
 149      * If {@code Cursor} is {@code null} no exception is thrown and
 150      * the default drag cursor behavior is activated for this drag operation.
 151      * <br>
 152      * If {@code Image} is {@code null} no exception is thrown.
 153      * <br>
 154      * If {@code Image} is not {@code null} and the offset is
 155      * {@code null NullPointerException} is thrown.
 156      * <br>
 157      * If {@code Transferable} is {@code null}
 158      * {@code NullPointerException} is thrown.
 159      * <br>
 160      * If {@code DragSourceListener} is {@code null} no exception
 161      * is thrown.
 162      *
 163      * @param trigger    the triggering event
 164      * @param dragCursor     the initial {@code Cursor} for this drag operation
 165      *                       or {@code null} for the default cursor handling;
 166      *                       see <a href="DragSourceContext.html#defaultCursor">class level documentation</a>
 167      *                       for more details on the cursor handling mechanism during drag and drop
 168      * @param dragImage  the {@code Image} to drag (or {@code null})
 169      * @param offset     the offset of the image origin from the hotspot at the
 170      *                   instant of the triggering event
 171      * @param t          the {@code Transferable}
 172      * @param dsl        the {@code DragSourceListener}
 173      *
 174      * @throws IllegalArgumentException if the {@code Component} associated
 175      *         with the trigger event is {@code null}.
 176      * @throws IllegalArgumentException if the {@code DragSource} for the
 177      *         trigger event is {@code null}.
 178      * @throws IllegalArgumentException if the drag action for the
 179      *         trigger event is {@code DnDConstants.ACTION_NONE}.
 180      * @throws IllegalArgumentException if the source actions for the
 181      *         {@code DragGestureRecognizer} associated with the trigger
 182      *         event are equal to {@code DnDConstants.ACTION_NONE}.
 183      * @throws NullPointerException if dscp, trigger, or t are null, or
 184      *         if dragImage is non-null and offset is null
 185      */
 186     public DragSourceContext(DragGestureEvent trigger, Cursor dragCursor,
 187                              Image dragImage, Point offset, Transferable t,
 188                              DragSourceListener dsl) {
 189         Toolkit toolkit = Toolkit.getDefaultToolkit();
 190         if (!(toolkit instanceof ComponentFactory)) {
 191             throw new AWTError("Unsupported toolkit: " + toolkit);
 192         }
 193         DragSourceContextPeer dscp = ((ComponentFactory) toolkit).
 194                 createDragSourceContextPeer(trigger);
 195 
 196         if (dscp == null) {
 197             throw new NullPointerException("DragSourceContextPeer");
 198         }
 199 
 200         if (trigger == null) {
 201             throw new NullPointerException("Trigger");
 202         }


 223         }
 224 
 225         if (dragImage != null && offset == null) {
 226             throw new NullPointerException("offset");
 227         }
 228 
 229         peer         = dscp;
 230         this.trigger = trigger;
 231         cursor       = dragCursor;
 232         transferable = t;
 233         listener     = dsl;
 234         sourceActions =
 235             trigger.getSourceAsDragGestureRecognizer().getSourceActions();
 236 
 237         useCustomCursor = (dragCursor != null);
 238 
 239         updateCurrentCursor(trigger.getDragAction(), getSourceActions(), DEFAULT);
 240     }
 241 
 242     /**
 243      * Returns the {@code DragSource}
 244      * that instantiated this {@code DragSourceContext}.
 245      *
 246      * @return the {@code DragSource} that
 247      *   instantiated this {@code DragSourceContext}
 248      */
 249 
 250     public DragSource   getDragSource() { return trigger.getDragSource(); }
 251 
 252     /**
 253      * Returns the {@code Component} associated with this
 254      * {@code DragSourceContext}.
 255      *
 256      * @return the {@code Component} that started the drag
 257      */
 258 
 259     public Component    getComponent() { return trigger.getComponent(); }
 260 
 261     /**
 262      * Returns the {@code DragGestureEvent}
 263      * that initially triggered the drag.
 264      *
 265      * @return the Event that triggered the drag
 266      */
 267 
 268     public DragGestureEvent getTrigger() { return trigger; }
 269 
 270     /**
 271      * Returns a bitwise mask of {@code DnDConstants} that
 272      * represent the set of drop actions supported by the drag source for the
 273      * drag operation associated with this {@code DragSourceContext}.
 274      *
 275      * @return the drop actions supported by the drag source
 276      */
 277     public int  getSourceActions() {
 278         return sourceActions;
 279     }
 280 
 281     /**
 282      * Sets the cursor for this drag operation to the specified
 283      * {@code Cursor}.  If the specified {@code Cursor}
 284      * is {@code null}, the default drag cursor behavior is
 285      * activated for this drag operation, otherwise it is deactivated.
 286      *
 287      * @param c     the initial {@code Cursor} for this drag operation,
 288      *                       or {@code null} for the default cursor handling;
 289      *                       see {@linkplain Cursor class
 290      *                       level documentation} for more details
 291      *                       on the cursor handling during drag and drop
 292      *
 293      */
 294 
 295     public synchronized void setCursor(Cursor c) {
 296         useCustomCursor = (c != null);
 297         setCursorImpl(c);
 298     }
 299 
 300     /**
 301      * Returns the current drag {@code Cursor}.
 302      *
 303      * @return the current drag {@code Cursor}
 304      */
 305 
 306     public Cursor getCursor() { return cursor; }
 307 
 308     /**
 309      * Add a {@code DragSourceListener} to this
 310      * {@code DragSourceContext} if one has not already been added.
 311      * If a {@code DragSourceListener} already exists,
 312      * this method throws a {@code TooManyListenersException}.
 313      *
 314      * @param dsl the {@code DragSourceListener} to add.
 315      * Note that while {@code null} is not prohibited,
 316      * it is not acceptable as a parameter.
 317      *
 318      * @throws TooManyListenersException if
 319      * a {@code DragSourceListener} has already been added
 320      */
 321 
 322     public synchronized void addDragSourceListener(DragSourceListener dsl) throws TooManyListenersException {
 323         if (dsl == null) return;
 324 
 325         if (equals(dsl)) throw new IllegalArgumentException("DragSourceContext may not be its own listener");
 326 
 327         if (listener != null)
 328             throw new TooManyListenersException();
 329         else
 330             listener = dsl;
 331     }
 332 
 333     /**
 334      * Removes the specified {@code DragSourceListener}
 335      * from  this {@code DragSourceContext}.
 336      *
 337      * @param dsl the {@code DragSourceListener} to remove;
 338      *     note that while {@code null} is not prohibited,
 339      *     it is not acceptable as a parameter
 340      */
 341 
 342     public synchronized void removeDragSourceListener(DragSourceListener dsl) {
 343         if (listener != null && listener.equals(dsl)) {
 344             listener = null;
 345         } else
 346             throw new IllegalArgumentException();
 347     }
 348 
 349     /**
 350      * Notifies the peer that the {@code Transferable}'s
 351      * {@code DataFlavor}s have changed.
 352      */
 353 
 354     public void transferablesFlavorsChanged() {
 355         if (peer != null) peer.transferablesFlavorsChanged();
 356     }
 357 
 358     /**
 359      * Calls {@code dragEnter} on the
 360      * {@code DragSourceListener}s registered with this
 361      * {@code DragSourceContext} and with the associated
 362      * {@code DragSource}, and passes them the specified
 363      * {@code DragSourceDragEvent}.
 364      *
 365      * @param dsde the {@code DragSourceDragEvent}
 366      */
 367     public void dragEnter(DragSourceDragEvent dsde) {
 368         DragSourceListener dsl = listener;
 369         if (dsl != null) {
 370             dsl.dragEnter(dsde);
 371         }
 372         getDragSource().processDragEnter(dsde);
 373 
 374         updateCurrentCursor(getSourceActions(), dsde.getTargetActions(), ENTER);
 375     }
 376 
 377     /**
 378      * Calls {@code dragOver} on the
 379      * {@code DragSourceListener}s registered with this
 380      * {@code DragSourceContext} and with the associated
 381      * {@code DragSource}, and passes them the specified
 382      * {@code DragSourceDragEvent}.
 383      *
 384      * @param dsde the {@code DragSourceDragEvent}
 385      */
 386     public void dragOver(DragSourceDragEvent dsde) {
 387         DragSourceListener dsl = listener;
 388         if (dsl != null) {
 389             dsl.dragOver(dsde);
 390         }
 391         getDragSource().processDragOver(dsde);
 392 
 393         updateCurrentCursor(getSourceActions(), dsde.getTargetActions(), OVER);
 394     }
 395 
 396     /**
 397      * Calls {@code dragExit} on the
 398      * {@code DragSourceListener}s registered with this
 399      * {@code DragSourceContext} and with the associated
 400      * {@code DragSource}, and passes them the specified
 401      * {@code DragSourceEvent}.
 402      *
 403      * @param dse the {@code DragSourceEvent}
 404      */
 405     public void dragExit(DragSourceEvent dse) {
 406         DragSourceListener dsl = listener;
 407         if (dsl != null) {
 408             dsl.dragExit(dse);
 409         }
 410         getDragSource().processDragExit(dse);
 411 
 412         updateCurrentCursor(DnDConstants.ACTION_NONE, DnDConstants.ACTION_NONE, DEFAULT);
 413     }
 414 
 415     /**
 416      * Calls {@code dropActionChanged} on the
 417      * {@code DragSourceListener}s registered with this
 418      * {@code DragSourceContext} and with the associated
 419      * {@code DragSource}, and passes them the specified
 420      * {@code DragSourceDragEvent}.
 421      *
 422      * @param dsde the {@code DragSourceDragEvent}
 423      */
 424     public void dropActionChanged(DragSourceDragEvent dsde) {
 425         DragSourceListener dsl = listener;
 426         if (dsl != null) {
 427             dsl.dropActionChanged(dsde);
 428         }
 429         getDragSource().processDropActionChanged(dsde);
 430 
 431         updateCurrentCursor(getSourceActions(), dsde.getTargetActions(), CHANGED);
 432     }
 433 
 434     /**
 435      * Calls {@code dragDropEnd} on the
 436      * {@code DragSourceListener}s registered with this
 437      * {@code DragSourceContext} and with the associated
 438      * {@code DragSource}, and passes them the specified
 439      * {@code DragSourceDropEvent}.
 440      *
 441      * @param dsde the {@code DragSourceDropEvent}
 442      */
 443     public void dragDropEnd(DragSourceDropEvent dsde) {
 444         DragSourceListener dsl = listener;
 445         if (dsl != null) {
 446             dsl.dragDropEnd(dsde);
 447         }
 448         getDragSource().processDragDropEnd(dsde);
 449     }
 450 
 451     /**
 452      * Calls {@code dragMouseMoved} on the
 453      * {@code DragSourceMotionListener}s registered with the
 454      * {@code DragSource} associated with this
 455      * {@code DragSourceContext}, and them passes the specified
 456      * {@code DragSourceDragEvent}.
 457      *
 458      * @param dsde the {@code DragSourceDragEvent}
 459      * @since 1.4
 460      */
 461     public void dragMouseMoved(DragSourceDragEvent dsde) {
 462         getDragSource().processDragMouseMoved(dsde);
 463     }
 464 
 465     /**
 466      * Returns the {@code Transferable} associated with
 467      * this {@code DragSourceContext}.
 468      *
 469      * @return the {@code Transferable}
 470      */
 471     public Transferable getTransferable() { return transferable; }
 472 
 473     /**
 474      * If the default drag cursor behavior is active, this method
 475      * sets the default drag cursor for the specified actions
 476      * supported by the drag source, the drop target action,
 477      * and status, otherwise this method does nothing.
 478      *
 479      * @param sourceAct the actions supported by the drag source
 480      * @param targetAct the drop target action
 481      * @param status one of the fields {@code DEFAULT},
 482      *               {@code ENTER}, {@code OVER},
 483      *               {@code CHANGED}
 484      */
 485     @SuppressWarnings("fallthrough")
 486     protected synchronized void updateCurrentCursor(int sourceAct, int targetAct, int status) {
 487 
 488         // if the cursor has been previously set then don't do any defaults
 489         // processing.
 490 
 491         if (useCustomCursor) {
 492             return;
 493         }
 494 
 495         // do defaults processing
 496 
 497         Cursor c = null;
 498 
 499         switch (status) {
 500             default:
 501                 targetAct = DnDConstants.ACTION_NONE;
 502             case ENTER:
 503             case OVER:


 515                     if ((ra & DnDConstants.ACTION_LINK) == DnDConstants.ACTION_LINK)
 516                         c = DragSource.DefaultLinkDrop;
 517                     else if ((ra & DnDConstants.ACTION_MOVE) == DnDConstants.ACTION_MOVE)
 518                         c = DragSource.DefaultMoveDrop;
 519                     else
 520                         c = DragSource.DefaultCopyDrop;
 521                 }
 522         }
 523 
 524         setCursorImpl(c);
 525     }
 526 
 527     private void setCursorImpl(Cursor c) {
 528         if (cursor == null || !cursor.equals(c)) {
 529             cursor = c;
 530             if (peer != null) peer.setCursor(cursor);
 531         }
 532     }
 533 
 534     /**
 535      * Serializes this {@code DragSourceContext}. This method first
 536      * performs default serialization. Next, this object's
 537      * {@code Transferable} is written out if and only if it can be
 538      * serialized. If not, {@code null} is written instead. In this case,
 539      * a {@code DragSourceContext} created from the resulting deserialized
 540      * stream will contain a dummy {@code Transferable} which supports no
 541      * {@code DataFlavor}s. Finally, this object's
 542      * {@code DragSourceListener} is written out if and only if it can be
 543      * serialized. If not, {@code null} is written instead.
 544      *
 545      * @serialData The default serializable fields, in alphabetical order,
 546      *             followed by either a {@code Transferable} instance, or
 547      *             {@code null}, followed by either a
 548      *             {@code DragSourceListener} instance, or
 549      *             {@code null}.
 550      * @since 1.4
 551      */
 552     private void writeObject(ObjectOutputStream s) throws IOException {
 553         s.defaultWriteObject();
 554 
 555         s.writeObject(SerializationTester.test(transferable)
 556                       ? transferable : null);
 557         s.writeObject(SerializationTester.test(listener)
 558                       ? listener : null);
 559     }
 560 
 561     /**
 562      * Deserializes this {@code DragSourceContext}. This method first
 563      * performs default deserialization for all non-{@code transient}
 564      * fields. This object's {@code Transferable} and
 565      * {@code DragSourceListener} are then deserialized as well by using
 566      * the next two objects in the stream. If the resulting
 567      * {@code Transferable} is {@code null}, this object's
 568      * {@code Transferable} is set to a dummy {@code Transferable}
 569      * which supports no {@code DataFlavor}s.
 570      *
 571      * @since 1.4
 572      */
 573     private void readObject(ObjectInputStream s)
 574         throws ClassNotFoundException, IOException
 575     {
 576         ObjectInputStream.GetField f = s.readFields();
 577 
 578         DragGestureEvent newTrigger = (DragGestureEvent)f.get("trigger", null);
 579         if (newTrigger == null) {
 580             throw new InvalidObjectException("Null trigger");
 581         }
 582         if (newTrigger.getDragSource() == null) {
 583             throw new InvalidObjectException("Null DragSource");
 584         }
 585         if (newTrigger.getComponent() == null) {
 586             throw new InvalidObjectException("Null trigger component");
 587         }
 588 
 589         int newSourceActions = f.get("sourceActions", 0)


 637 
 638     /**
 639      * The event which triggered the start of the drag.
 640      *
 641      * @serial
 642      */
 643     private DragGestureEvent    trigger;
 644 
 645     /**
 646      * The current drag cursor.
 647      *
 648      * @serial
 649      */
 650     private Cursor              cursor;
 651 
 652     private transient Transferable      transferable;
 653 
 654     private transient DragSourceListener    listener;
 655 
 656     /**
 657      * {@code true} if the custom drag cursor is used instead of the
 658      * default one.
 659      *
 660      * @serial
 661      */
 662     private boolean useCustomCursor;
 663 
 664     /**
 665      * A bitwise mask of {@code DnDConstants} that represents the set of
 666      * drop actions supported by the drag source for the drag operation associated
 667      * with this {@code DragSourceContext.}
 668      *
 669      * @serial
 670      */
 671     private int sourceActions;
 672 }
< prev index next >