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