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 26package java.awt.dnd; 27 28import java.awt.Component; 29import java.awt.Cursor; 30import java.awt.GraphicsEnvironment; 31import java.awt.HeadlessException; 32import java.awt.Image; 33import java.awt.Point; 34import java.awt.Toolkit; 35import java.awt.datatransfer.FlavorMap; 36import java.awt.datatransfer.SystemFlavorMap; 37import java.awt.datatransfer.Transferable; 38import java.io.IOException; 39import java.io.ObjectInputStream; 40import java.io.ObjectOutputStream; 41import java.io.Serializable; 42import java.security.AccessController; 43import java.util.EventListener; 44 45import sun.awt.AWTAccessor; 46import sun.awt.AWTAccessor.DragSourceContextAccessor; 47import sun.awt.dnd.SunDragSourceContextPeer; 48import sun.security.action.GetIntegerAction; 49 50 51/** 52 * The {@code DragSource} is the entity responsible 53 * for the initiation of the Drag 54 * and Drop operation, and may be used in a number of scenarios: 55 * <UL> 56 * <LI>1 default instance per JVM for the lifetime of that JVM. 57 * <LI>1 instance per class of potential Drag Initiator object (e.g 58 * TextField). [implementation dependent] 59 * <LI>1 per instance of a particular 60 * {@code Component}, or application specific 61 * object associated with a {@code Component} 62 * instance in the GUI. [implementation dependent] 63 * <LI>Some other arbitrary association. [implementation dependent] 64 *</UL> 65 * 66 * Once the {@code DragSource} is 67 * obtained, a {@code DragGestureRecognizer} should 68 * also be obtained to associate the {@code DragSource} 69 * with a particular 70 * {@code Component}. 71 * <P> 72 * The initial interpretation of the user's gesture, 73 * and the subsequent starting of the drag operation 74 * are the responsibility of the implementing 75 * {@code Component}, which is usually 76 * implemented by a {@code DragGestureRecognizer}. 77 *<P> 78 * When a drag gesture occurs, the 79 * {@code DragSource}'s 80 * startDrag() method shall be 81 * invoked in order to cause processing 82 * of the user's navigational 83 * gestures and delivery of Drag and Drop 84 * protocol notifications. A 85 * {@code DragSource} shall only 86 * permit a single Drag and Drop operation to be 87 * current at any one time, and shall 88 * reject any further startDrag() requests 89 * by throwing an {@code IllegalDnDOperationException} 90 * until such time as the extant operation is complete. 91 * <P> 92 * The startDrag() method invokes the 93 * createDragSourceContext() method to 94 * instantiate an appropriate 95 * {@code DragSourceContext} 96 * and associate the {@code DragSourceContextPeer} 97 * with that. 98 * <P> 99 * If the Drag and Drop System is 100 * unable to initiate a drag operation for 101 * some reason, the startDrag() method throws 102 * a {@code java.awt.dnd.InvalidDnDOperationException} 103 * to signal such a condition. Typically this 104 * exception is thrown when the underlying platform 105 * system is either not in a state to 106 * initiate a drag, or the parameters specified are invalid. 107 * <P> 108 * Note that during the drag, the 109 * set of operations exposed by the source 110 * at the start of the drag operation may not change 111 * until the operation is complete. 112 * The operation(s) are constant for the 113 * duration of the operation with respect to the 114 * {@code DragSource}. 115 * 116 * @since 1.2 117 */ 118 119public class DragSource implements Serializable { 120 121 private static final long serialVersionUID = 6236096958971414066L; 122 123 /* 124 * load a system default cursor 125 */ 126 127 private static Cursor load(String name) { 128 if (GraphicsEnvironment.isHeadless()) { 129 return null; 130 } 131 132 try { 133 return (Cursor)Toolkit.getDefaultToolkit().getDesktopProperty(name); 134 } catch (Exception e) { 135 e.printStackTrace(); 136 137 throw new RuntimeException("failed to load system cursor: " + name + " : " + e.getMessage()); 138 } 139 } 140 141 142 /** 143 * The default {@code Cursor} to use with a copy operation indicating 144 * that a drop is currently allowed. {@code null} if 145 * {@code GraphicsEnvironment.isHeadless()} returns {@code true}. 146 * 147 * @see java.awt.GraphicsEnvironment#isHeadless 148 */ 149 public static final Cursor DefaultCopyDrop = 150 load("DnD.Cursor.CopyDrop"); 151 152 /** 153 * The default {@code Cursor} to use with a move operation indicating 154 * that a drop is currently allowed. {@code null} if 155 * {@code GraphicsEnvironment.isHeadless()} returns {@code true}. 156 * 157 * @see java.awt.GraphicsEnvironment#isHeadless 158 */ 159 public static final Cursor DefaultMoveDrop = 160 load("DnD.Cursor.MoveDrop"); 161 162 /** 163 * The default {@code Cursor} to use with a link operation indicating 164 * that a drop is currently allowed. {@code null} if 165 * {@code GraphicsEnvironment.isHeadless()} returns {@code true}. 166 * 167 * @see java.awt.GraphicsEnvironment#isHeadless 168 */ 169 public static final Cursor DefaultLinkDrop = 170 load("DnD.Cursor.LinkDrop"); 171 172 /** 173 * The default {@code Cursor} to use with a copy operation indicating 174 * that a drop is currently not allowed. {@code null} if 175 * {@code GraphicsEnvironment.isHeadless()} returns {@code true}. 176 * 177 * @see java.awt.GraphicsEnvironment#isHeadless 178 */ 179 public static final Cursor DefaultCopyNoDrop = 180 load("DnD.Cursor.CopyNoDrop"); 181 182 /** 183 * The default {@code Cursor} to use with a move operation indicating 184 * that a drop is currently not allowed. {@code null} if 185 * {@code GraphicsEnvironment.isHeadless()} returns {@code true}. 186 * 187 * @see java.awt.GraphicsEnvironment#isHeadless 188 */ 189 public static final Cursor DefaultMoveNoDrop = 190 load("DnD.Cursor.MoveNoDrop"); 191 192 /** 193 * The default {@code Cursor} to use with a link operation indicating 194 * that a drop is currently not allowed. {@code null} if 195 * {@code GraphicsEnvironment.isHeadless()} returns {@code true}. 196 * 197 * @see java.awt.GraphicsEnvironment#isHeadless 198 */ 199 public static final Cursor DefaultLinkNoDrop = 200 load("DnD.Cursor.LinkNoDrop"); 201 202 private static final DragSource dflt = 203 (GraphicsEnvironment.isHeadless()) ? null : new DragSource(); 204 205 /** 206 * Internal constants for serialization. 207 */ 208 static final String dragSourceListenerK = "dragSourceL"; 209 static final String dragSourceMotionListenerK = "dragSourceMotionL"; 210 211 /** 212 * Gets the {@code DragSource} object associated with 213 * the underlying platform. 214 * 215 * @return the platform DragSource 216 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 217 * returns true 218 * @see java.awt.GraphicsEnvironment#isHeadless 219 */ 220 public static DragSource getDefaultDragSource() { 221 if (GraphicsEnvironment.isHeadless()) { 222 throw new HeadlessException(); 223 } else { 224 return dflt; 225 } 226 } 227 228 /** 229 * Reports 230 * whether or not drag 231 * {@code Image} support 232 * is available on the underlying platform. 233 * 234 * @return if the Drag Image support is available on this platform 235 */ 236 237 public static boolean isDragImageSupported() { 238 Toolkit t = Toolkit.getDefaultToolkit(); 239 240 Boolean supported; 241 242 try { 243 supported = (Boolean)Toolkit.getDefaultToolkit().getDesktopProperty("DnD.isDragImageSupported"); 244 245 return supported.booleanValue(); 246 } catch (Exception e) { 247 return false; 248 } 249 } 250 251 /** 252 * Creates a new {@code DragSource}. 253 * 254 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 255 * returns true 256 * @see java.awt.GraphicsEnvironment#isHeadless 257 */ 258 public DragSource() throws HeadlessException { 259 if (GraphicsEnvironment.isHeadless()) { 260 throw new HeadlessException(); 261 } 262 } 263 264 /** 265 * Start a drag, given the {@code DragGestureEvent} 266 * that initiated the drag, the initial 267 * {@code Cursor} to use, 268 * the {@code Image} to drag, 269 * the offset of the {@code Image} origin 270 * from the hotspot of the {@code Cursor} at 271 * the instant of the trigger, 272 * the {@code Transferable} subject data 273 * of the drag, the {@code DragSourceListener}, 274 * and the {@code FlavorMap}. 275 * 276 * @param trigger the {@code DragGestureEvent} that initiated the drag 277 * @param dragCursor the initial {@code Cursor} for this drag operation 278 * or {@code null} for the default cursor handling; 279 * see <a href="DragSourceContext.html#defaultCursor">DragSourceContext</a> 280 * for more details on the cursor handling mechanism during drag and drop 281 * @param dragImage the image to drag or {@code null} 282 * @param imageOffset the offset of the {@code Image} origin from the hotspot 283 * of the {@code Cursor} at the instant of the trigger 284 * @param transferable the subject data of the drag 285 * @param dsl the {@code DragSourceListener} 286 * @param flavorMap the {@code FlavorMap} to use, or {@code null} 287 * 288 * @throws java.awt.dnd.InvalidDnDOperationException 289 * if the Drag and Drop 290 * system is unable to initiate a drag operation, or if the user 291 * attempts to start a drag while an existing drag operation 292 * is still executing 293 */ 294 295 public void startDrag(DragGestureEvent trigger, 296 Cursor dragCursor, 297 Image dragImage, 298 Point imageOffset, 299 Transferable transferable, 300 DragSourceListener dsl, 301 FlavorMap flavorMap) throws InvalidDnDOperationException { 302 303 SunDragSourceContextPeer.setDragDropInProgress(true); 304 305 try { 306 if (flavorMap != null) this.flavorMap = flavorMap; 307 308 DragSourceContext dsc = createDragSourceContext(trigger, dragCursor, 309 dragImage, 310 imageOffset, 311 transferable, dsl); 312 313 if (dsc == null) { 314 throw new InvalidDnDOperationException(); 315 } 316 DragSourceContextAccessor acc = AWTAccessor.getDragSourceContextAccessor(); 317 acc.getPeer(dsc).startDrag(dsc, dsc.getCursor(), dragImage, imageOffset); // may throw 318 } catch (RuntimeException e) { 319 SunDragSourceContextPeer.setDragDropInProgress(false); 320 throw e; 321 } 322 } 323 324 /** 325 * Start a drag, given the {@code DragGestureEvent} 326 * that initiated the drag, the initial 327 * {@code Cursor} to use, 328 * the {@code Transferable} subject data 329 * of the drag, the {@code DragSourceListener}, 330 * and the {@code FlavorMap}. 331 * 332 * @param trigger the {@code DragGestureEvent} that 333 * initiated the drag 334 * @param dragCursor the initial {@code Cursor} for this drag operation 335 * or {@code null} for the default cursor handling; 336 * see <a href="DragSourceContext.html#defaultCursor">DragSourceContext</a> 337 * for more details on the cursor handling mechanism during drag and drop 338 * @param transferable the subject data of the drag 339 * @param dsl the {@code DragSourceListener} 340 * @param flavorMap the {@code FlavorMap} to use or {@code null} 341 * 342 * @throws java.awt.dnd.InvalidDnDOperationException 343 * if the Drag and Drop 344 * system is unable to initiate a drag operation, or if the user 345 * attempts to start a drag while an existing drag operation 346 * is still executing 347 */ 348 349 public void startDrag(DragGestureEvent trigger, 350 Cursor dragCursor, 351 Transferable transferable, 352 DragSourceListener dsl, 353 FlavorMap flavorMap) throws InvalidDnDOperationException { 354 startDrag(trigger, dragCursor, null, null, transferable, dsl, flavorMap); 355 } 356 357 /** 358 * Start a drag, given the {@code DragGestureEvent} 359 * that initiated the drag, the initial {@code Cursor} 360 * to use, 361 * the {@code Image} to drag, 362 * the offset of the {@code Image} origin 363 * from the hotspot of the {@code Cursor} 364 * at the instant of the trigger, 365 * the subject data of the drag, and 366 * the {@code DragSourceListener}. 367 * 368 * @param trigger the {@code DragGestureEvent} that initiated the drag 369 * @param dragCursor the initial {@code Cursor} for this drag operation 370 * or {@code null} for the default cursor handling; 371 * see <a href="DragSourceContext.html#defaultCursor">DragSourceContext</a> 372 * for more details on the cursor handling mechanism during drag and drop 373 * @param dragImage the {@code Image} to drag or {@code null} 374 * @param dragOffset the offset of the {@code Image} origin from the hotspot 375 * of the {@code Cursor} at the instant of the trigger 376 * @param transferable the subject data of the drag 377 * @param dsl the {@code DragSourceListener} 378 * 379 * @throws java.awt.dnd.InvalidDnDOperationException 380 * if the Drag and Drop 381 * system is unable to initiate a drag operation, or if the user 382 * attempts to start a drag while an existing drag operation 383 * is still executing 384 */ 385 386 public void startDrag(DragGestureEvent trigger, 387 Cursor dragCursor, 388 Image dragImage, 389 Point dragOffset, 390 Transferable transferable, 391 DragSourceListener dsl) throws InvalidDnDOperationException { 392 startDrag(trigger, dragCursor, dragImage, dragOffset, transferable, dsl, null); 393 } 394 395 /** 396 * Start a drag, given the {@code DragGestureEvent} 397 * that initiated the drag, the initial 398 * {@code Cursor} to 399 * use, 400 * the {@code Transferable} subject data 401 * of the drag, and the {@code DragSourceListener}. 402 * 403 * @param trigger the {@code DragGestureEvent} that initiated the drag 404 * @param dragCursor the initial {@code Cursor} for this drag operation 405 * or {@code null} for the default cursor handling; 406 * see <a href="DragSourceContext.html#defaultCursor">DragSourceContext</a> class 407 * for more details on the cursor handling mechanism during drag and drop 408 * @param transferable the subject data of the drag 409 * @param dsl the {@code DragSourceListener} 410 * 411 * @throws java.awt.dnd.InvalidDnDOperationException 412 * if the Drag and Drop 413 * system is unable to initiate a drag operation, or if the user 414 * attempts to start a drag while an existing drag operation 415 * is still executing 416 */ 417 418 public void startDrag(DragGestureEvent trigger, 419 Cursor dragCursor, 420 Transferable transferable, 421 DragSourceListener dsl) throws InvalidDnDOperationException { 422 startDrag(trigger, dragCursor, null, null, transferable, dsl, null); 423 } 424 425 /** 426 * Creates the {@code DragSourceContext} to handle the current drag 427 * operation. 428 * <p> 429 * To incorporate a new {@code DragSourceContext} 430 * subclass, subclass {@code DragSource} and 431 * override this method. 432 * <p> 433 * If {@code dragImage} is {@code null}, no image is used 434 * to represent the drag over feedback for this drag operation, but 435 * {@code NullPointerException} is not thrown. 436 * <p> 437 * If {@code dsl} is {@code null}, no drag source listener 438 * is registered with the created {@code DragSourceContext}, 439 * but {@code NullPointerException} is not thrown. 440 * 441 * @param dgl The {@code DragGestureEvent} that triggered the 442 * drag 443 * @param dragCursor The initial {@code Cursor} for this drag operation 444 * or {@code null} for the default cursor handling; 445 * see <a href="DragSourceContext.html#defaultCursor">DragSourceContext</a> class 446 * for more details on the cursor handling mechanism during drag and drop 447 * @param dragImage The {@code Image} to drag or {@code null} 448 * @param imageOffset The offset of the {@code Image} origin from the 449 * hotspot of the cursor at the instant of the trigger 450 * @param t The subject data of the drag 451 * @param dsl The {@code DragSourceListener} 452 * 453 * @return the {@code DragSourceContext} 454 * 455 * @throws NullPointerException if {@code dscp} is {@code null} 456 * @throws NullPointerException if {@code dgl} is {@code null} 457 * @throws NullPointerException if {@code dragImage} is not 458 * {@code null} and {@code imageOffset} is {@code null} 459 * @throws NullPointerException if {@code t} is {@code null} 460 * @throws IllegalArgumentException if the {@code Component} 461 * associated with the trigger event is {@code null}. 462 * @throws IllegalArgumentException if the {@code DragSource} for the 463 * trigger event is {@code null}. 464 * @throws IllegalArgumentException if the drag action for the 465 * trigger event is {@code DnDConstants.ACTION_NONE}. 466 * @throws IllegalArgumentException if the source actions for the 467 * {@code DragGestureRecognizer} associated with the trigger 468 * event are equal to {@code DnDConstants.ACTION_NONE}. 469 */ 470 471 protected DragSourceContext createDragSourceContext(DragGestureEvent dgl, 472 Cursor dragCursor, 473 Image dragImage, 474 Point imageOffset, 475 Transferable t, 476 DragSourceListener dsl) { 477 return new DragSourceContext(dgl, dragCursor, dragImage, imageOffset, t, dsl); 478 } 479 480 /** 481 * This method returns the 482 * {@code FlavorMap} for this {@code DragSource}. 483 * 484 * @return the {@code FlavorMap} for this {@code DragSource} 485 */ 486 487 public FlavorMap getFlavorMap() { return flavorMap; } 488 489 /** 490 * Creates a new {@code DragGestureRecognizer} 491 * that implements the specified 492 * abstract subclass of 493 * {@code DragGestureRecognizer}, and 494 * sets the specified {@code Component} 495 * and {@code DragGestureListener} on 496 * the newly created object. 497 * 498 * @param <T> the type of {@code DragGestureRecognizer} to create 499 * @param recognizerAbstractClass the requested abstract type 500 * @param actions the permitted source drag actions 501 * @param c the {@code Component} target 502 * @param dgl the {@code DragGestureListener} to notify 503 * 504 * @return the new {@code DragGestureRecognizer} or {@code null} 505 * if the {@code Toolkit.createDragGestureRecognizer} method 506 * has no implementation available for 507 * the requested {@code DragGestureRecognizer} 508 * subclass and returns {@code null} 509 */ 510 511 public <T extends DragGestureRecognizer> T 512 createDragGestureRecognizer(Class<T> recognizerAbstractClass, 513 Component c, int actions, 514 DragGestureListener dgl) 515 { 516 return Toolkit.getDefaultToolkit().createDragGestureRecognizer(recognizerAbstractClass, this, c, actions, dgl); 517 } 518 519 520 /** 521 * Creates a new {@code DragGestureRecognizer} 522 * that implements the default 523 * abstract subclass of {@code DragGestureRecognizer} 524 * for this {@code DragSource}, 525 * and sets the specified {@code Component} 526 * and {@code DragGestureListener} on the 527 * newly created object. 528 * 529 * For this {@code DragSource} 530 * the default is {@code MouseDragGestureRecognizer}. 531 * 532 * @param c the {@code Component} target for the recognizer 533 * @param actions the permitted source actions 534 * @param dgl the {@code DragGestureListener} to notify 535 * 536 * @return the new {@code DragGestureRecognizer} or {@code null} 537 * if the {@code Toolkit.createDragGestureRecognizer} method 538 * has no implementation available for 539 * the requested {@code DragGestureRecognizer} 540 * subclass and returns {@code null} 541 */ 542 543 public DragGestureRecognizer createDefaultDragGestureRecognizer(Component c, int actions, DragGestureListener dgl) { 544 return Toolkit.getDefaultToolkit().createDragGestureRecognizer(MouseDragGestureRecognizer.class, this, c, actions, dgl); 545 } 546 547 /** 548 * Adds the specified {@code DragSourceListener} to this 549 * {@code DragSource} to receive drag source events during drag 550 * operations initiated with this {@code DragSource}. 551 * If a {@code null} listener is specified, no action is taken and no 552 * exception is thrown. 553 * 554 * @param dsl the {@code DragSourceListener} to add 555 * 556 * @see #removeDragSourceListener 557 * @see #getDragSourceListeners 558 * @since 1.4 559 */ 560 public void addDragSourceListener(DragSourceListener dsl) { 561 if (dsl != null) { 562 synchronized (this) { 563 listener = DnDEventMulticaster.add(listener, dsl); 564 } 565 } 566 } 567 568 /** 569 * Removes the specified {@code DragSourceListener} from this 570 * {@code DragSource}. 571 * If a {@code null} listener is specified, no action is taken and no 572 * exception is thrown. 573 * If the listener specified by the argument was not previously added to 574 * this {@code DragSource}, no action is taken and no exception 575 * is thrown. 576 * 577 * @param dsl the {@code DragSourceListener} to remove 578 * 579 * @see #addDragSourceListener 580 * @see #getDragSourceListeners 581 * @since 1.4 582 */ 583 public void removeDragSourceListener(DragSourceListener dsl) { 584 if (dsl != null) { 585 synchronized (this) { 586 listener = DnDEventMulticaster.remove(listener, dsl); 587 } 588 } 589 } 590 591 /** 592 * Gets all the {@code DragSourceListener}s 593 * registered with this {@code DragSource}. 594 * 595 * @return all of this {@code DragSource}'s 596 * {@code DragSourceListener}s or an empty array if no 597 * such listeners are currently registered 598 * 599 * @see #addDragSourceListener 600 * @see #removeDragSourceListener 601 * @since 1.4 602 */ 603 public DragSourceListener[] getDragSourceListeners() { 604 return getListeners(DragSourceListener.class); 605 } 606 607 /** 608 * Adds the specified {@code DragSourceMotionListener} to this 609 * {@code DragSource} to receive drag motion events during drag 610 * operations initiated with this {@code DragSource}. 611 * If a {@code null} listener is specified, no action is taken and no 612 * exception is thrown. 613 * 614 * @param dsml the {@code DragSourceMotionListener} to add 615 * 616 * @see #removeDragSourceMotionListener 617 * @see #getDragSourceMotionListeners 618 * @since 1.4 619 */ 620 public void addDragSourceMotionListener(DragSourceMotionListener dsml) { 621 if (dsml != null) { 622 synchronized (this) { 623 motionListener = DnDEventMulticaster.add(motionListener, dsml); 624 } 625 } 626 } 627 628 /** 629 * Removes the specified {@code DragSourceMotionListener} from this 630 * {@code DragSource}. 631 * If a {@code null} listener is specified, no action is taken and no 632 * exception is thrown. 633 * If the listener specified by the argument was not previously added to 634 * this {@code DragSource}, no action is taken and no exception 635 * is thrown. 636 * 637 * @param dsml the {@code DragSourceMotionListener} to remove 638 * 639 * @see #addDragSourceMotionListener 640 * @see #getDragSourceMotionListeners 641 * @since 1.4 642 */ 643 public void removeDragSourceMotionListener(DragSourceMotionListener dsml) { 644 if (dsml != null) { 645 synchronized (this) { 646 motionListener = DnDEventMulticaster.remove(motionListener, dsml); 647 } 648 } 649 } 650 651 /** 652 * Gets all of the {@code DragSourceMotionListener}s 653 * registered with this {@code DragSource}. 654 * 655 * @return all of this {@code DragSource}'s 656 * {@code DragSourceMotionListener}s or an empty array if no 657 * such listeners are currently registered 658 * 659 * @see #addDragSourceMotionListener 660 * @see #removeDragSourceMotionListener 661 * @since 1.4 662 */ 663 public DragSourceMotionListener[] getDragSourceMotionListeners() { 664 return getListeners(DragSourceMotionListener.class); 665 } 666 667 /** 668 * Gets all the objects currently registered as 669 * <code><em>Foo</em>Listener</code>s upon this {@code DragSource}. 670 * <code><em>Foo</em>Listener</code>s are registered using the 671 * <code>add<em>Foo</em>Listener</code> method. 672 * 673 * @param <T> the type of listener objects 674 * @param listenerType the type of listeners requested; this parameter 675 * should specify an interface that descends from 676 * {@code java.util.EventListener} 677 * @return an array of all objects registered as 678 * <code><em>Foo</em>Listener</code>s on this 679 * {@code DragSource}, or an empty array if no such listeners 680 * have been added 681 * @exception ClassCastException if {@code listenerType} 682 * doesn't specify a class or interface that implements 683 * {@code java.util.EventListener} 684 * 685 * @see #getDragSourceListeners 686 * @see #getDragSourceMotionListeners 687 * @since 1.4 688 */ 689 public <T extends EventListener> T[] getListeners(Class<T> listenerType) { 690 EventListener l = null; 691 if (listenerType == DragSourceListener.class) { 692 l = listener; 693 } else if (listenerType == DragSourceMotionListener.class) { 694 l = motionListener; 695 } 696 return DnDEventMulticaster.getListeners(l, listenerType); 697 } 698 699 /** 700 * This method calls {@code dragEnter} on the 701 * {@code DragSourceListener}s registered with this 702 * {@code DragSource}, and passes them the specified 703 * {@code DragSourceDragEvent}. 704 * 705 * @param dsde the {@code DragSourceDragEvent} 706 */ 707 void processDragEnter(DragSourceDragEvent dsde) { 708 DragSourceListener dsl = listener; 709 if (dsl != null) { 710 dsl.dragEnter(dsde); 711 } 712 } 713 714 /** 715 * This method calls {@code dragOver} on the 716 * {@code DragSourceListener}s registered with this 717 * {@code DragSource}, and passes them the specified 718 * {@code DragSourceDragEvent}. 719 * 720 * @param dsde the {@code DragSourceDragEvent} 721 */ 722 void processDragOver(DragSourceDragEvent dsde) { 723 DragSourceListener dsl = listener; 724 if (dsl != null) { 725 dsl.dragOver(dsde); 726 } 727 } 728 729 /** 730 * This method calls {@code dropActionChanged} on the 731 * {@code DragSourceListener}s registered with this 732 * {@code DragSource}, and passes them the specified 733 * {@code DragSourceDragEvent}. 734 * 735 * @param dsde the {@code DragSourceDragEvent} 736 */ 737 void processDropActionChanged(DragSourceDragEvent dsde) { 738 DragSourceListener dsl = listener; 739 if (dsl != null) { 740 dsl.dropActionChanged(dsde); 741 } 742 } 743 744 /** 745 * This method calls {@code dragExit} on the 746 * {@code DragSourceListener}s registered with this 747 * {@code DragSource}, and passes them the specified 748 * {@code DragSourceEvent}. 749 * 750 * @param dse the {@code DragSourceEvent} 751 */ 752 void processDragExit(DragSourceEvent dse) { 753 DragSourceListener dsl = listener; 754 if (dsl != null) { 755 dsl.dragExit(dse); 756 } 757 } 758 759 /** 760 * This method calls {@code dragDropEnd} on the 761 * {@code DragSourceListener}s registered with this 762 * {@code DragSource}, and passes them the specified 763 * {@code DragSourceDropEvent}. 764 * 765 * @param dsde the {@code DragSourceEvent} 766 */ 767 void processDragDropEnd(DragSourceDropEvent dsde) { 768 DragSourceListener dsl = listener; 769 if (dsl != null) { 770 dsl.dragDropEnd(dsde); 771 } 772 } 773 774 /** 775 * This method calls {@code dragMouseMoved} on the 776 * {@code DragSourceMotionListener}s registered with this 777 * {@code DragSource}, and passes them the specified 778 * {@code DragSourceDragEvent}. 779 * 780 * @param dsde the {@code DragSourceEvent} 781 */ 782 void processDragMouseMoved(DragSourceDragEvent dsde) { 783 DragSourceMotionListener dsml = motionListener; 784 if (dsml != null) { 785 dsml.dragMouseMoved(dsde); 786 } 787 } 788 789 /** 790 * Serializes this {@code DragSource}. This method first performs 791 * default serialization. Next, it writes out this object's 792 * {@code FlavorMap} if and only if it can be serialized. If not, 793 * {@code null} is written instead. Next, it writes out 794 * {@code Serializable} listeners registered with this 795 * object. Listeners are written in a {@code null}-terminated sequence 796 * of 0 or more pairs. The pair consists of a {@code String} and an 797 * {@code Object}; the {@code String} indicates the type of the 798 * {@code Object} and is one of the following: 799 * <ul> 800 * <li>{@code dragSourceListenerK} indicating a 801 * {@code DragSourceListener} object; 802 * <li>{@code dragSourceMotionListenerK} indicating a 803 * {@code DragSourceMotionListener} object. 804 * </ul> 805 * 806 * @serialData Either a {@code FlavorMap} instance, or 807 * {@code null}, followed by a {@code null}-terminated 808 * sequence of 0 or more pairs; the pair consists of a 809 * {@code String} and an {@code Object}; the 810 * {@code String} indicates the type of the {@code Object} 811 * and is one of the following: 812 * <ul> 813 * <li>{@code dragSourceListenerK} indicating a 814 * {@code DragSourceListener} object; 815 * <li>{@code dragSourceMotionListenerK} indicating a 816 * {@code DragSourceMotionListener} object. 817 * </ul>. 818 * @since 1.4 819 */ 820 private void writeObject(ObjectOutputStream s) throws IOException { 821 s.defaultWriteObject(); 822 823 s.writeObject(SerializationTester.test(flavorMap) ? flavorMap : null); 824 825 DnDEventMulticaster.save(s, dragSourceListenerK, listener); 826 DnDEventMulticaster.save(s, dragSourceMotionListenerK, motionListener); 827 s.writeObject(null); 828 } 829 830 /** 831 * Deserializes this {@code DragSource}. This method first performs 832 * default deserialization. Next, this object's {@code FlavorMap} is 833 * deserialized by using the next object in the stream. 834 * If the resulting {@code FlavorMap} is {@code null}, this 835 * object's {@code FlavorMap} is set to the default FlavorMap for 836 * this thread's {@code ClassLoader}. 837 * Next, this object's listeners are deserialized by reading a 838 * {@code null}-terminated sequence of 0 or more key/value pairs 839 * from the stream: 840 * <ul> 841 * <li>If a key object is a {@code String} equal to 842 * {@code dragSourceListenerK}, a {@code DragSourceListener} is 843 * deserialized using the corresponding value object and added to this 844 * {@code DragSource}. 845 * <li>If a key object is a {@code String} equal to 846 * {@code dragSourceMotionListenerK}, a 847 * {@code DragSourceMotionListener} is deserialized using the 848 * corresponding value object and added to this {@code DragSource}. 849 * <li>Otherwise, the key/value pair is skipped. 850 * </ul> 851 * 852 * @see java.awt.datatransfer.SystemFlavorMap#getDefaultFlavorMap 853 * @since 1.4 854 */ 855 private void readObject(ObjectInputStream s) 856 throws ClassNotFoundException, IOException { 857 s.defaultReadObject(); 858 859 // 'flavorMap' was written explicitly 860 flavorMap = (FlavorMap)s.readObject(); 861 862 // Implementation assumes 'flavorMap' is never null. 863 if (flavorMap == null) { 864 flavorMap = SystemFlavorMap.getDefaultFlavorMap(); 865 } 866 867 Object keyOrNull; 868 while (null != (keyOrNull = s.readObject())) { 869 String key = ((String)keyOrNull).intern(); 870 871 if (dragSourceListenerK == key) { 872 addDragSourceListener((DragSourceListener)(s.readObject())); 873 } else if (dragSourceMotionListenerK == key) { 874 addDragSourceMotionListener( 875 (DragSourceMotionListener)(s.readObject())); 876 } else { 877 // skip value for unrecognized key 878 s.readObject(); 879 } 880 } 881 } 882 883 /** 884 * Returns the drag gesture motion threshold. The drag gesture motion threshold 885 * defines the recommended behavior for {@link MouseDragGestureRecognizer}s. 886 * <p> 887 * If the system property {@code awt.dnd.drag.threshold} is set to 888 * a positive integer, this method returns the value of the system property; 889 * otherwise if a pertinent desktop property is available and supported by 890 * the implementation of the Java platform, this method returns the value of 891 * that property; otherwise this method returns some default value. 892 * The pertinent desktop property can be queried using 893 * {@code java.awt.Toolkit.getDesktopProperty("DnD.gestureMotionThreshold")}. 894 * 895 * @return the drag gesture motion threshold 896 * @see MouseDragGestureRecognizer 897 * @since 1.5 898 */ 899 public static int getDragThreshold() { 900 int ts = AccessController.doPrivileged( 901 new GetIntegerAction("awt.dnd.drag.threshold", 0)).intValue(); 902 if (ts > 0) { 903 return ts; 904 } else { 905 Integer td = (Integer)Toolkit.getDefaultToolkit(). 906 getDesktopProperty("DnD.gestureMotionThreshold"); 907 if (td != null) { 908 return td.intValue(); 909 } 910 } 911 return 5; 912 } 913 914 /* 915 * fields 916 */ 917 918 private transient FlavorMap flavorMap = SystemFlavorMap.getDefaultFlavorMap(); 919 920 private transient DragSourceListener listener; 921 922 private transient DragSourceMotionListener motionListener; 923} 924