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.Component; 29 import java.awt.Cursor; 30 import java.awt.GraphicsEnvironment; 31 import java.awt.HeadlessException; 32 import java.awt.Image; 33 import java.awt.Point; 34 import java.awt.Toolkit; 35 import java.awt.datatransfer.FlavorMap; 36 import java.awt.datatransfer.SystemFlavorMap; 37 import java.awt.datatransfer.Transferable; 38 import java.io.IOException; 39 import java.io.ObjectInputStream; 40 import java.io.ObjectOutputStream; 41 import java.io.Serializable; 42 import java.security.AccessController; 43 import java.util.EventListener; 44 45 import sun.awt.AWTAccessor; 46 import sun.awt.AWTAccessor.DragSourceContextAccessor; 47 import sun.awt.dnd.SunDragSourceContextPeer; 48 import 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 119 public class DragSource implements Serializable { 120 121 private static final long serialVersionUID = 6236096958971414066L; 122 123 /* 124 * load a system default cursor 125 */ 126 load(String name)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 */ getDefaultDragSource()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 isDragImageSupported()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 */ DragSource()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 startDrag(DragGestureEvent trigger, Cursor dragCursor, Image dragImage, Point imageOffset, Transferable transferable, DragSourceListener dsl, FlavorMap flavorMap)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 startDrag(DragGestureEvent trigger, Cursor dragCursor, Transferable transferable, DragSourceListener dsl, FlavorMap flavorMap)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 startDrag(DragGestureEvent trigger, Cursor dragCursor, Image dragImage, Point dragOffset, Transferable transferable, DragSourceListener dsl)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 startDrag(DragGestureEvent trigger, Cursor dragCursor, Transferable transferable, DragSourceListener dsl)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 createDragSourceContext(DragGestureEvent dgl, Cursor dragCursor, Image dragImage, Point imageOffset, Transferable t, DragSourceListener dsl)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 getFlavorMap()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 createDragGestureRecognizer(Class<T> recognizerAbstractClass, Component c, int actions, DragGestureListener dgl)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 createDefaultDragGestureRecognizer(Component c, int actions, DragGestureListener dgl)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 */ addDragSourceListener(DragSourceListener dsl)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 */ removeDragSourceListener(DragSourceListener dsl)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 */ getDragSourceListeners()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 */ addDragSourceMotionListener(DragSourceMotionListener dsml)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 */ removeDragSourceMotionListener(DragSourceMotionListener dsml)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 */ getDragSourceMotionListeners()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 */ getListeners(Class<T> listenerType)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 */ processDragEnter(DragSourceDragEvent dsde)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 */ processDragOver(DragSourceDragEvent dsde)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 */ processDropActionChanged(DragSourceDragEvent dsde)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 */ processDragExit(DragSourceEvent dse)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 */ processDragDropEnd(DragSourceDropEvent dsde)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 */ processDragMouseMoved(DragSourceDragEvent dsde)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 */ writeObject(ObjectOutputStream s)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 */ readObject(ObjectInputStream s)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 */ getDragThreshold()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