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 }