1 /*
   2  * Copyright (c) 1998, 2006, 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.event.InputEvent;
  29 import java.awt.Component;
  30 import java.awt.Point;
  31 
  32 import java.util.TooManyListenersException;
  33 import java.util.ArrayList;
  34 
  35 import java.io.IOException;
  36 import java.io.ObjectInputStream;
  37 import java.io.ObjectOutputStream;
  38 import java.io.Serializable;
  39 
  40 /**
  41  * The <code>DragGestureRecognizer</code> is an
  42  * abstract base class for the specification
  43  * of a platform-dependent listener that can be associated with a particular
  44  * <code>Component</code> in order to
  45  * identify platform-dependent drag initiating gestures.
  46  * <p>
  47  * The appropriate <code>DragGestureRecognizer</code>
  48  * subclass instance is obtained from the
  49  * {@link DragSource} asssociated with
  50  * a particular <code>Component</code>, or from the <code>Toolkit</code> object via its
  51  * {@link java.awt.Toolkit#createDragGestureRecognizer createDragGestureRecognizer()}
  52  * method.
  53  * <p>
  54  * Once the <code>DragGestureRecognizer</code>
  55  * is associated with a particular <code>Component</code>
  56  * it will register the appropriate listener interfaces on that
  57  * <code>Component</code>
  58  * in order to track the input events delivered to the <code>Component</code>.
  59  * <p>
  60  * Once the <code>DragGestureRecognizer</code> identifies a sequence of events
  61  * on the <code>Component</code> as a drag initiating gesture, it will notify
  62  * its unicast <code>DragGestureListener</code> by
  63  * invoking its
  64  * {@link java.awt.dnd.DragGestureListener#dragGestureRecognized gestureRecognized()}
  65  * method.
  66  * <P>
  67  * When a concrete <code>DragGestureRecognizer</code>
  68  * instance detects a drag initiating
  69  * gesture on the <code>Component</code> it is associated with,
  70  * it fires a {@link DragGestureEvent} to
  71  * the <code>DragGestureListener</code> registered on
  72  * its unicast event source for <code>DragGestureListener</code>
  73  * events. This <code>DragGestureListener</code> is responsible
  74  * for causing the associated
  75  * <code>DragSource</code> to start the Drag and Drop operation (if
  76  * appropriate).
  77  * <P>
  78  * @author Laurence P. G. Cable
  79  * @see java.awt.dnd.DragGestureListener
  80  * @see java.awt.dnd.DragGestureEvent
  81  * @see java.awt.dnd.DragSource
  82  */
  83 
  84 public abstract class DragGestureRecognizer implements Serializable {
  85 
  86     private static final long serialVersionUID = 8996673345831063337L;
  87 
  88     /**
  89      * Construct a new <code>DragGestureRecognizer</code>
  90      * given the <code>DragSource</code> to be used
  91      * in this Drag and Drop operation, the <code>Component</code>
  92      * this <code>DragGestureRecognizer</code> should "observe"
  93      * for drag initiating gestures, the action(s) supported
  94      * for this Drag and Drop operation, and the
  95      * <code>DragGestureListener</code> to notify
  96      * once a drag initiating gesture has been detected.
  97      * <P>
  98      * @param ds  the <code>DragSource</code> this
  99      * <code>DragGestureRecognizer</code>
 100      * will use to process the Drag and Drop operation
 101      *
 102      * @param c the <code>Component</code>
 103      * this <code>DragGestureRecognizer</code>
 104      * should "observe" the event stream to,
 105      * in order to detect a drag initiating gesture.
 106      * If this value is <code>null</code>, the
 107      * <code>DragGestureRecognizer</code>
 108      * is not associated with any <code>Component</code>.
 109      *
 110      * @param sa  the set (logical OR) of the
 111      * <code>DnDConstants</code>
 112      * that this Drag and Drop operation will support
 113      *
 114      * @param dgl the <code>DragGestureRecognizer</code>
 115      * to notify when a drag gesture is detected
 116      * <P>
 117      * @throws <code>IllegalArgumentException</code>
 118      * if ds is <code>null</code>.
 119      */
 120 
 121     protected DragGestureRecognizer(DragSource ds, Component c, int sa, DragGestureListener dgl) {
 122         super();
 123 
 124         if (ds == null) throw new IllegalArgumentException("null DragSource");
 125 
 126         dragSource    = ds;
 127         component     = c;
 128         sourceActions = sa & (DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_LINK);
 129 
 130         try {
 131             if (dgl != null) addDragGestureListener(dgl);
 132         } catch (TooManyListenersException tmle) {
 133             // cant happen ...
 134         }
 135     }
 136 
 137     /**
 138      * Construct a new <code>DragGestureRecognizer</code>
 139      * given the <code>DragSource</code> to be used in this
 140      * Drag and Drop
 141      * operation, the <code>Component</code> this
 142      * <code>DragGestureRecognizer</code> should "observe"
 143      * for drag initiating gestures, and the action(s)
 144      * supported for this Drag and Drop operation.
 145      * <P>
 146      * @param ds  the <code>DragSource</code> this
 147      * <code>DragGestureRecognizer</code> will use to
 148      * process the Drag and Drop operation
 149      *
 150      * @param c   the <code>Component</code> this
 151      * <code>DragGestureRecognizer</code> should "observe" the event
 152      * stream to, in order to detect a drag initiating gesture.
 153      * If this value is <code>null</code>, the
 154      * <code>DragGestureRecognizer</code>
 155      * is not associated with any <code>Component</code>.
 156      *
 157      * @param sa the set (logical OR) of the <code>DnDConstants</code>
 158      * that this Drag and Drop operation will support
 159      * <P>
 160      * @throws <code>IllegalArgumentException</code>
 161      * if ds is <code>null</code>.
 162      */
 163 
 164     protected DragGestureRecognizer(DragSource ds, Component c, int sa) {
 165         this(ds, c, sa, null);
 166     }
 167 
 168     /**
 169      * Construct a new <code>DragGestureRecognizer</code>
 170      * given the <code>DragSource</code> to be used
 171      * in this Drag and Drop operation, and
 172      * the <code>Component</code> this
 173      * <code>DragGestureRecognizer</code>
 174      * should "observe" for drag initiating gestures.
 175      * <P>
 176      * @param ds the <code>DragSource</code> this
 177      * <code>DragGestureRecognizer</code>
 178      * will use to process the Drag and Drop operation
 179      *
 180      * @param c the <code>Component</code>
 181      * this <code>DragGestureRecognizer</code>
 182      * should "observe" the event stream to,
 183      * in order to detect a drag initiating gesture.
 184      * If this value is <code>null</code>,
 185      * the <code>DragGestureRecognizer</code>
 186      * is not associated with any <code>Component</code>.
 187      * <P>
 188      * @throws <code>IllegalArgumentException</code>
 189      * if ds is <code>null</code>.
 190      */
 191 
 192     protected DragGestureRecognizer(DragSource ds, Component c) {
 193         this(ds, c, DnDConstants.ACTION_NONE);
 194     }
 195 
 196     /**
 197      * Construct a new <code>DragGestureRecognizer</code>
 198      * given the <code>DragSource</code> to be used in this
 199      * Drag and Drop operation.
 200      * <P>
 201      * @param ds the <code>DragSource</code> this
 202      * <code>DragGestureRecognizer</code> will
 203      * use to process the Drag and Drop operation
 204      * <P>
 205      * @throws <code>IllegalArgumentException</code>
 206      * if ds is <code>null</code>.
 207      */
 208 
 209     protected DragGestureRecognizer(DragSource ds) {
 210         this(ds, null);
 211     }
 212 
 213     /**
 214      * register this DragGestureRecognizer's Listeners with the Component
 215      *
 216      * subclasses must override this method
 217      */
 218 
 219     protected abstract void registerListeners();
 220 
 221     /**
 222      * unregister this DragGestureRecognizer's Listeners with the Component
 223      *
 224      * subclasses must override this method
 225      */
 226 
 227     protected abstract void unregisterListeners();
 228 
 229     /**
 230      * This method returns the <code>DragSource</code>
 231      * this <code>DragGestureRecognizer</code>
 232      * will use in order to process the Drag and Drop
 233      * operation.
 234      * <P>
 235      * @return the DragSource
 236      */
 237 
 238     public DragSource getDragSource() { return dragSource; }
 239 
 240     /**
 241      * This method returns the <code>Component</code>
 242      * that is to be "observed" by the
 243      * <code>DragGestureRecognizer</code>
 244      * for drag initiating gestures.
 245      * <P>
 246      * @return The Component this DragGestureRecognizer
 247      * is associated with
 248      */
 249 
 250     public synchronized Component getComponent() { return component; }
 251 
 252     /**
 253      * set the Component that the DragGestureRecognizer is associated with
 254      *
 255      * registerListeners() and unregisterListeners() are called as a side
 256      * effect as appropriate.
 257      * <P>
 258      * @param c The <code>Component</code> or <code>null</code>
 259      */
 260 
 261     public synchronized void setComponent(Component c) {
 262         if (component != null && dragGestureListener != null)
 263             unregisterListeners();
 264 
 265         component = c;
 266 
 267         if (component != null && dragGestureListener != null)
 268             registerListeners();
 269     }
 270 
 271     /**
 272      * This method returns an int representing the
 273      * type of action(s) this Drag and Drop
 274      * operation will support.
 275      * <P>
 276      * @return the currently permitted source action(s)
 277      */
 278 
 279     public synchronized int getSourceActions() { return sourceActions; }
 280 
 281     /**
 282      * This method sets the permitted source drag action(s)
 283      * for this Drag and Drop operation.
 284      * <P>
 285      * @param actions the permitted source drag action(s)
 286      */
 287 
 288     public synchronized void setSourceActions(int actions) {
 289         sourceActions = actions & (DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_LINK);
 290     }
 291 
 292     /**
 293      * This method returns the first event in the
 294      * series of events that initiated
 295      * the Drag and Drop operation.
 296      * <P>
 297      * @return the initial event that triggered the drag gesture
 298      */
 299 
 300     public InputEvent getTriggerEvent() { return events.isEmpty() ? null : (InputEvent)events.get(0); }
 301 
 302     /**
 303      * Reset the Recognizer, if its currently recognizing a gesture, ignore
 304      * it.
 305      */
 306 
 307     public void resetRecognizer() { events.clear(); }
 308 
 309     /**
 310      * Register a new <code>DragGestureListener</code>.
 311      * <P>
 312      * @param dgl the <code>DragGestureListener</code> to register
 313      * with this <code>DragGestureRecognizer</code>.
 314      * <P>
 315      * @throws java.util.TooManyListenersException if a
 316      * <code>DragGestureListener</code> has already been added.
 317      */
 318 
 319     public synchronized void addDragGestureListener(DragGestureListener dgl) throws TooManyListenersException {
 320         if (dragGestureListener != null)
 321             throw new TooManyListenersException();
 322         else {
 323             dragGestureListener = dgl;
 324 
 325             if (component != null) registerListeners();
 326         }
 327     }
 328 
 329     /**
 330      * unregister the current DragGestureListener
 331      * <P>
 332      * @param dgl the <code>DragGestureListener</code> to unregister
 333      * from this <code>DragGestureRecognizer</code>
 334      * <P>
 335      * @throws <code>IllegalArgumentException</code> if
 336      * dgl is not (equal to) the currently registered <code>DragGestureListener</code>.
 337      */
 338 
 339     public synchronized void removeDragGestureListener(DragGestureListener dgl) {
 340         if (dragGestureListener == null || !dragGestureListener.equals(dgl))
 341             throw new IllegalArgumentException();
 342         else {
 343             dragGestureListener = null;
 344 
 345             if (component != null) unregisterListeners();
 346         }
 347     }
 348 
 349     /**
 350      * Notify the DragGestureListener that a Drag and Drop initiating
 351      * gesture has occurred. Then reset the state of the Recognizer.
 352      * <P>
 353      * @param dragAction The action initially selected by the users gesture
 354      * @param p          The point (in Component coords) where the gesture originated
 355      */
 356     protected synchronized void fireDragGestureRecognized(int dragAction, Point p) {
 357         try {
 358             if (dragGestureListener != null) {
 359                 dragGestureListener.dragGestureRecognized(new DragGestureEvent(this, dragAction, p, events));
 360             }
 361         } finally {
 362             events.clear();
 363         }
 364     }
 365 
 366     /**
 367      * Listeners registered on the Component by this Recognizer shall record
 368      * all Events that are recognized as part of the series of Events that go
 369      * to comprise a Drag and Drop initiating gesture via this API.
 370      *<P>
 371      * This method is used by a <code>DragGestureRecognizer</code>
 372      * implementation to add an <code>InputEvent</code>
 373      * subclass (that it believes is one in a series
 374      * of events that comprise a Drag and Drop operation)
 375      * to the array of events that this
 376      * <code>DragGestureRecognizer</code> maintains internally.
 377      * <P>
 378      * @param awtie the <code>InputEvent</code>
 379      * to add to this <code>DragGestureRecognizer</code>'s
 380      * internal array of events. Note that <code>null</code>
 381      * is not a valid value, and will be ignored.
 382      */
 383 
 384     protected synchronized void appendEvent(InputEvent awtie) {
 385         events.add(awtie);
 386     }
 387 
 388     /**
 389      * Serializes this <code>DragGestureRecognizer</code>. This method first
 390      * performs default serialization. Then, this object's
 391      * <code>DragGestureListener</code> is written out if and only if it can be
 392      * serialized. If not, <code>null</code> is written instead.
 393      *
 394      * @serialData The default serializable fields, in alphabetical order,
 395      *             followed by either a <code>DragGestureListener</code>, or
 396      *             <code>null</code>.
 397      * @since 1.4
 398      */
 399     private void writeObject(ObjectOutputStream s) throws IOException {
 400         s.defaultWriteObject();
 401 
 402         s.writeObject(SerializationTester.test(dragGestureListener)
 403                       ? dragGestureListener : null);
 404     }
 405 
 406     /**
 407      * Deserializes this <code>DragGestureRecognizer</code>. This method first
 408      * performs default deserialization for all non-<code>transient</code>
 409      * fields. This object's <code>DragGestureListener</code> is then
 410      * deserialized as well by using the next object in the stream.
 411      *
 412      * @since 1.4
 413      */
 414     private void readObject(ObjectInputStream s)
 415         throws ClassNotFoundException, IOException
 416     {
 417         s.defaultReadObject();
 418 
 419         dragGestureListener = (DragGestureListener)s.readObject();
 420     }
 421 
 422     /*
 423      * fields
 424      */
 425 
 426     /**
 427      * The <code>DragSource</code>
 428      * associated with this
 429      * <code>DragGestureRecognizer</code>.
 430      *
 431      * @serial
 432      */
 433     protected DragSource          dragSource;
 434 
 435     /**
 436      * The <code>Component</code>
 437      * associated with this <code>DragGestureRecognizer</code>.
 438      *
 439      * @serial
 440      */
 441     protected Component           component;
 442 
 443     /**
 444      * The <code>DragGestureListener</code>
 445      * associated with this <code>DragGestureRecognizer</code>.
 446      */
 447     protected transient DragGestureListener dragGestureListener;
 448 
 449   /**
 450    * An <code>int</code> representing
 451    * the type(s) of action(s) used
 452    * in this Drag and Drop operation.
 453    *
 454    * @serial
 455    */
 456   protected int  sourceActions;
 457 
 458    /**
 459     * The list of events (in order) that
 460     * the <code>DragGestureRecognizer</code>
 461     * "recognized" as a "gesture" that triggers a drag.
 462     *
 463     * @serial
 464     */
 465    protected ArrayList<InputEvent> events = new ArrayList<InputEvent>(1);
 466 }