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