1 /*
   2  * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.awt.dnd;
  27 
  28 import java.awt.AWTError;
  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         }
 203 
 204         if (trigger.getDragSource() == null) {
 205             throw new IllegalArgumentException("DragSource");
 206         }
 207 
 208         if (trigger.getComponent() == null) {
 209             throw new IllegalArgumentException("Component");
 210         }
 211 
 212         if (trigger.getSourceAsDragGestureRecognizer().getSourceActions() ==
 213                  DnDConstants.ACTION_NONE) {
 214             throw new IllegalArgumentException("source actions");
 215         }
 216 
 217         if (trigger.getDragAction() == DnDConstants.ACTION_NONE) {
 218             throw new IllegalArgumentException("no drag action");
 219         }
 220 
 221         if (t == null) {
 222             throw new NullPointerException("Transferable");
 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:
 504             case CHANGED:
 505                 int    ra = sourceAct & targetAct;
 506 
 507                 if (ra == DnDConstants.ACTION_NONE) { // no drop possible
 508                     if ((sourceAct & DnDConstants.ACTION_LINK) == DnDConstants.ACTION_LINK)
 509                         c = DragSource.DefaultLinkNoDrop;
 510                     else if ((sourceAct & DnDConstants.ACTION_MOVE) == DnDConstants.ACTION_MOVE)
 511                         c = DragSource.DefaultMoveNoDrop;
 512                     else
 513                         c = DragSource.DefaultCopyNoDrop;
 514                 } else { // drop possible
 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)
 590                 & (DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_LINK);
 591         if (newSourceActions == DnDConstants.ACTION_NONE) {
 592             throw new InvalidObjectException("Invalid source actions");
 593         }
 594         int triggerActions = newTrigger.getDragAction();
 595         if (triggerActions != DnDConstants.ACTION_COPY &&
 596                 triggerActions != DnDConstants.ACTION_MOVE &&
 597                 triggerActions != DnDConstants.ACTION_LINK) {
 598             throw new InvalidObjectException("No drag action");
 599         }
 600         trigger = newTrigger;
 601 
 602         cursor = (Cursor)f.get("cursor", null);
 603         useCustomCursor = f.get("useCustomCursor", false);
 604         sourceActions = newSourceActions;
 605 
 606         transferable = (Transferable)s.readObject();
 607         listener = (DragSourceListener)s.readObject();
 608 
 609         // Implementation assumes 'transferable' is never null.
 610         if (transferable == null) {
 611             if (emptyTransferable == null) {
 612                 emptyTransferable = new Transferable() {
 613                         public DataFlavor[] getTransferDataFlavors() {
 614                             return new DataFlavor[0];
 615                         }
 616                         public boolean isDataFlavorSupported(DataFlavor flavor)
 617                         {
 618                             return false;
 619                         }
 620                         public Object getTransferData(DataFlavor flavor)
 621                             throws UnsupportedFlavorException
 622                         {
 623                             throw new UnsupportedFlavorException(flavor);
 624                         }
 625                     };
 626             }
 627             transferable = emptyTransferable;
 628         }
 629     }
 630 
 631     private static Transferable emptyTransferable;
 632 
 633     /*
 634      * fields
 635      */
 636     private final transient DragSourceContextPeer peer;
 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 }