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.util.TooManyListenersException; 29 30 import java.io.IOException; 31 import java.io.ObjectInputStream; 32 import java.io.ObjectOutputStream; 33 import java.io.Serializable; 34 35 import java.awt.Component; 36 import java.awt.Dimension; 37 import java.awt.GraphicsEnvironment; 38 import java.awt.HeadlessException; 39 import java.awt.Insets; 40 import java.awt.Point; 41 import java.awt.Rectangle; 42 import java.awt.Toolkit; 43 import java.awt.event.ActionEvent; 44 import java.awt.event.ActionListener; 45 import java.awt.datatransfer.FlavorMap; 46 import java.awt.datatransfer.SystemFlavorMap; 47 import javax.swing.Timer; 48 import java.awt.peer.ComponentPeer; 49 import java.awt.peer.LightweightPeer; 50 import java.awt.dnd.peer.DropTargetPeer; 51 52 import sun.awt.AWTAccessor; 53 import sun.awt.AWTAccessor.ComponentAccessor; 54 55 56 /** 57 * The <code>DropTarget</code> is associated 58 * with a <code>Component</code> when that <code>Component</code> 59 * wishes 60 * to accept drops during Drag and Drop operations. 61 * <P> 62 * Each 63 * <code>DropTarget</code> is associated with a <code>FlavorMap</code>. 64 * The default <code>FlavorMap</code> hereafter designates the 65 * <code>FlavorMap</code> returned by <code>SystemFlavorMap.getDefaultFlavorMap()</code>. 66 * 67 * @since 1.2 68 */ 69 70 public class DropTarget implements DropTargetListener, Serializable { 71 72 private static final long serialVersionUID = -6283860791671019047L; 73 74 /** 75 * Creates a new DropTarget given the <code>Component</code> 76 * to associate itself with, an <code>int</code> representing 77 * the default acceptable action(s) to 78 * support, a <code>DropTargetListener</code> 79 * to handle event processing, a <code>boolean</code> indicating 80 * if the <code>DropTarget</code> is currently accepting drops, and 81 * a <code>FlavorMap</code> to use (or null for the default <CODE>FlavorMap</CODE>). 82 * <P> 83 * The Component will receive drops only if it is enabled. 84 * @param c The <code>Component</code> with which this <code>DropTarget</code> is associated 85 * @param ops The default acceptable actions for this <code>DropTarget</code> 86 * @param dtl The <code>DropTargetListener</code> for this <code>DropTarget</code> 87 * @param act Is the <code>DropTarget</code> accepting drops. 88 * @param fm The <code>FlavorMap</code> to use, or null for the default <CODE>FlavorMap</CODE> 89 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 90 * returns true 91 * @see java.awt.GraphicsEnvironment#isHeadless 92 */ 93 public DropTarget(Component c, int ops, DropTargetListener dtl, 94 boolean act, FlavorMap fm) 95 throws HeadlessException 96 { 97 if (GraphicsEnvironment.isHeadless()) { 98 throw new HeadlessException(); 99 } 100 101 component = c; 102 103 setDefaultActions(ops); 104 105 if (dtl != null) try { 106 addDropTargetListener(dtl); 107 } catch (TooManyListenersException tmle) { 108 // do nothing! 109 } 110 111 if (c != null) { 112 c.setDropTarget(this); 113 setActive(act); 114 } 115 116 if (fm != null) { 117 flavorMap = fm; 118 } else { 119 flavorMap = SystemFlavorMap.getDefaultFlavorMap(); 120 } 121 } 122 123 /** 124 * Creates a <code>DropTarget</code> given the <code>Component</code> 125 * to associate itself with, an <code>int</code> representing 126 * the default acceptable action(s) 127 * to support, a <code>DropTargetListener</code> 128 * to handle event processing, and a <code>boolean</code> indicating 129 * if the <code>DropTarget</code> is currently accepting drops. 130 * <P> 131 * The Component will receive drops only if it is enabled. 132 * @param c The <code>Component</code> with which this <code>DropTarget</code> is associated 133 * @param ops The default acceptable actions for this <code>DropTarget</code> 134 * @param dtl The <code>DropTargetListener</code> for this <code>DropTarget</code> 135 * @param act Is the <code>DropTarget</code> accepting drops. 136 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 137 * returns true 138 * @see java.awt.GraphicsEnvironment#isHeadless 139 */ 140 public DropTarget(Component c, int ops, DropTargetListener dtl, 141 boolean act) 142 throws HeadlessException 143 { 144 this(c, ops, dtl, act, null); 145 } 146 147 /** 148 * Creates a <code>DropTarget</code>. 149 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 150 * returns true 151 * @see java.awt.GraphicsEnvironment#isHeadless 152 */ 153 public DropTarget() throws HeadlessException { 154 this(null, DnDConstants.ACTION_COPY_OR_MOVE, null, true, null); 155 } 156 157 /** 158 * Creates a <code>DropTarget</code> given the <code>Component</code> 159 * to associate itself with, and the <code>DropTargetListener</code> 160 * to handle event processing. 161 * <P> 162 * The Component will receive drops only if it is enabled. 163 * @param c The <code>Component</code> with which this <code>DropTarget</code> is associated 164 * @param dtl The <code>DropTargetListener</code> for this <code>DropTarget</code> 165 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 166 * returns true 167 * @see java.awt.GraphicsEnvironment#isHeadless 168 */ 169 public DropTarget(Component c, DropTargetListener dtl) 170 throws HeadlessException 171 { 172 this(c, DnDConstants.ACTION_COPY_OR_MOVE, dtl, true, null); 173 } 174 175 /** 176 * Creates a <code>DropTarget</code> given the <code>Component</code> 177 * to associate itself with, an <code>int</code> representing 178 * the default acceptable action(s) to support, and a 179 * <code>DropTargetListener</code> to handle event processing. 180 * <P> 181 * The Component will receive drops only if it is enabled. 182 * @param c The <code>Component</code> with which this <code>DropTarget</code> is associated 183 * @param ops The default acceptable actions for this <code>DropTarget</code> 184 * @param dtl The <code>DropTargetListener</code> for this <code>DropTarget</code> 185 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 186 * returns true 187 * @see java.awt.GraphicsEnvironment#isHeadless 188 */ 189 public DropTarget(Component c, int ops, DropTargetListener dtl) 190 throws HeadlessException 191 { 192 this(c, ops, dtl, true); 193 } 194 195 /** 196 * Note: this interface is required to permit the safe association 197 * of a DropTarget with a Component in one of two ways, either: 198 * <code> component.setDropTarget(droptarget); </code> 199 * or <code> droptarget.setComponent(component); </code> 200 * <P> 201 * The Component will receive drops only if it is enabled. 202 * @param c The new <code>Component</code> this <code>DropTarget</code> 203 * is to be associated with. 204 */ 205 206 public synchronized void setComponent(Component c) { 207 if (component == c || component != null && component.equals(c)) 208 return; 209 210 final Component old = component; 211 212 if (old != null) { 213 clearAutoscroll(); 214 215 component = null; 216 removeNotify(); 217 old.setDropTarget(null); 218 219 } 220 221 if ((component = c) != null) try { 222 c.setDropTarget(this); 223 } catch (Exception e) { // undo the change 224 if (old != null) { 225 old.setDropTarget(this); 226 addNotify(); 227 } 228 } 229 } 230 231 /** 232 * Gets the <code>Component</code> associated 233 * with this <code>DropTarget</code>. 234 * 235 * @return the current <code>Component</code> 236 */ 237 238 public synchronized Component getComponent() { 239 return component; 240 } 241 242 /** 243 * Sets the default acceptable actions for this <code>DropTarget</code> 244 * 245 * @param ops the default actions 246 * @see java.awt.dnd.DnDConstants 247 */ 248 249 public void setDefaultActions(int ops) { 250 getDropTargetContext().setTargetActions(ops & (DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_REFERENCE)); 251 } 252 253 /* 254 * Called by DropTargetContext.setTargetActions() 255 * with appropriate synchronization. 256 */ 257 void doSetDefaultActions(int ops) { 258 actions = ops; 259 } 260 261 /** 262 * Gets an <code>int</code> representing the 263 * current action(s) supported by this <code>DropTarget</code>. 264 * 265 * @return the current default actions 266 */ 267 268 public int getDefaultActions() { 269 return actions; 270 } 271 272 /** 273 * Sets the DropTarget active if <code>true</code>, 274 * inactive if <code>false</code>. 275 * 276 * @param isActive sets the <code>DropTarget</code> (in)active. 277 */ 278 279 public synchronized void setActive(boolean isActive) { 280 if (isActive != active) { 281 active = isActive; 282 } 283 284 if (!active) clearAutoscroll(); 285 } 286 287 /** 288 * Reports whether or not 289 * this <code>DropTarget</code> 290 * is currently active (ready to accept drops). 291 * 292 * @return <CODE>true</CODE> if active, <CODE>false</CODE> if not 293 */ 294 295 public boolean isActive() { 296 return active; 297 } 298 299 /** 300 * Adds a new <code>DropTargetListener</code> (UNICAST SOURCE). 301 * 302 * @param dtl The new <code>DropTargetListener</code> 303 * 304 * @throws TooManyListenersException if a 305 * <code>DropTargetListener</code> is already added to this 306 * <code>DropTarget</code>. 307 */ 308 309 public synchronized void addDropTargetListener(DropTargetListener dtl) throws TooManyListenersException { 310 if (dtl == null) return; 311 312 if (equals(dtl)) throw new IllegalArgumentException("DropTarget may not be its own Listener"); 313 314 if (dtListener == null) 315 dtListener = dtl; 316 else 317 throw new TooManyListenersException(); 318 } 319 320 /** 321 * Removes the current <code>DropTargetListener</code> (UNICAST SOURCE). 322 * 323 * @param dtl the DropTargetListener to deregister. 324 */ 325 326 public synchronized void removeDropTargetListener(DropTargetListener dtl) { 327 if (dtl != null && dtListener != null) { 328 if(dtListener.equals(dtl)) 329 dtListener = null; 330 else 331 throw new IllegalArgumentException("listener mismatch"); 332 } 333 } 334 335 /** 336 * Calls <code>dragEnter</code> on the registered 337 * <code>DropTargetListener</code> and passes it 338 * the specified <code>DropTargetDragEvent</code>. 339 * Has no effect if this <code>DropTarget</code> 340 * is not active. 341 * 342 * @param dtde the <code>DropTargetDragEvent</code> 343 * 344 * @throws NullPointerException if this <code>DropTarget</code> 345 * is active and <code>dtde</code> is <code>null</code> 346 * 347 * @see #isActive 348 */ 349 public synchronized void dragEnter(DropTargetDragEvent dtde) { 350 isDraggingInside = true; 351 352 if (!active) return; 353 354 if (dtListener != null) { 355 dtListener.dragEnter(dtde); 356 } else 357 dtde.getDropTargetContext().setTargetActions(DnDConstants.ACTION_NONE); 358 359 initializeAutoscrolling(dtde.getLocation()); 360 } 361 362 /** 363 * Calls <code>dragOver</code> on the registered 364 * <code>DropTargetListener</code> and passes it 365 * the specified <code>DropTargetDragEvent</code>. 366 * Has no effect if this <code>DropTarget</code> 367 * is not active. 368 * 369 * @param dtde the <code>DropTargetDragEvent</code> 370 * 371 * @throws NullPointerException if this <code>DropTarget</code> 372 * is active and <code>dtde</code> is <code>null</code> 373 * 374 * @see #isActive 375 */ 376 public synchronized void dragOver(DropTargetDragEvent dtde) { 377 if (!active) return; 378 379 if (dtListener != null && active) dtListener.dragOver(dtde); 380 381 updateAutoscroll(dtde.getLocation()); 382 } 383 384 /** 385 * Calls <code>dropActionChanged</code> on the registered 386 * <code>DropTargetListener</code> and passes it 387 * the specified <code>DropTargetDragEvent</code>. 388 * Has no effect if this <code>DropTarget</code> 389 * is not active. 390 * 391 * @param dtde the <code>DropTargetDragEvent</code> 392 * 393 * @throws NullPointerException if this <code>DropTarget</code> 394 * is active and <code>dtde</code> is <code>null</code> 395 * 396 * @see #isActive 397 */ 398 public synchronized void dropActionChanged(DropTargetDragEvent dtde) { 399 if (!active) return; 400 401 if (dtListener != null) dtListener.dropActionChanged(dtde); 402 403 updateAutoscroll(dtde.getLocation()); 404 } 405 406 /** 407 * Calls <code>dragExit</code> on the registered 408 * <code>DropTargetListener</code> and passes it 409 * the specified <code>DropTargetEvent</code>. 410 * Has no effect if this <code>DropTarget</code> 411 * is not active. 412 * <p> 413 * This method itself does not throw any exception 414 * for null parameter but for exceptions thrown by 415 * the respective method of the listener. 416 * 417 * @param dte the <code>DropTargetEvent</code> 418 * 419 * @see #isActive 420 */ 421 public synchronized void dragExit(DropTargetEvent dte) { 422 isDraggingInside = false; 423 424 if (!active) return; 425 426 if (dtListener != null && active) dtListener.dragExit(dte); 427 428 clearAutoscroll(); 429 } 430 431 /** 432 * Calls <code>drop</code> on the registered 433 * <code>DropTargetListener</code> and passes it 434 * the specified <code>DropTargetDropEvent</code> 435 * if this <code>DropTarget</code> is active. 436 * 437 * @param dtde the <code>DropTargetDropEvent</code> 438 * 439 * @throws NullPointerException if <code>dtde</code> is null 440 * and at least one of the following is true: this 441 * <code>DropTarget</code> is not active, or there is 442 * no a <code>DropTargetListener</code> registered. 443 * 444 * @see #isActive 445 */ 446 public synchronized void drop(DropTargetDropEvent dtde) { 447 isDraggingInside = false; 448 449 clearAutoscroll(); 450 451 if (dtListener != null && active) 452 dtListener.drop(dtde); 453 else { // we shouldn't get here ... 454 dtde.rejectDrop(); 455 } 456 } 457 458 /** 459 * Gets the <code>FlavorMap</code> 460 * associated with this <code>DropTarget</code>. 461 * If no <code>FlavorMap</code> has been set for this 462 * <code>DropTarget</code>, it is associated with the default 463 * <code>FlavorMap</code>. 464 * 465 * @return the FlavorMap for this DropTarget 466 */ 467 468 public FlavorMap getFlavorMap() { return flavorMap; } 469 470 /** 471 * Sets the <code>FlavorMap</code> associated 472 * with this <code>DropTarget</code>. 473 * 474 * @param fm the new <code>FlavorMap</code>, or null to 475 * associate the default FlavorMap with this DropTarget. 476 */ 477 478 public void setFlavorMap(FlavorMap fm) { 479 flavorMap = fm == null ? SystemFlavorMap.getDefaultFlavorMap() : fm; 480 } 481 482 /** 483 * Notify the DropTarget that it has been associated with a Component 484 * 485 ********************************************************************** 486 * This method is usually called from java.awt.Component.addNotify() of 487 * the Component associated with this DropTarget to notify the DropTarget 488 * that a ComponentPeer has been associated with that Component. 489 * 490 * Calling this method, other than to notify this DropTarget of the 491 * association of the ComponentPeer with the Component may result in 492 * a malfunction of the DnD system. 493 ********************************************************************** 494 */ 495 public void addNotify() { 496 final ComponentAccessor acc = AWTAccessor.getComponentAccessor(); 497 ComponentPeer peer = acc.getPeer(component); 498 if (peer == null || peer == componentPeer) { 499 return; 500 } 501 502 componentPeer = peer; 503 504 505 for (Component c = component; 506 c != null && peer instanceof LightweightPeer; c = c.getParent()) { 507 peer = acc.getPeer(c); 508 } 509 510 if (peer instanceof DropTargetPeer) { 511 nativePeer = (DropTargetPeer) peer; 512 ((DropTargetPeer)peer).addDropTarget(this); 513 } else { 514 nativePeer = null; 515 } 516 } 517 518 /** 519 * Notify the DropTarget that it has been disassociated from a Component 520 * 521 ********************************************************************** 522 * This method is usually called from java.awt.Component.removeNotify() of 523 * the Component associated with this DropTarget to notify the DropTarget 524 * that a ComponentPeer has been disassociated with that Component. 525 * 526 * Calling this method, other than to notify this DropTarget of the 527 * disassociation of the ComponentPeer from the Component may result in 528 * a malfunction of the DnD system. 529 ********************************************************************** 530 */ 531 532 public void removeNotify() { 533 if (nativePeer != null) { 534 nativePeer.removeDropTarget(this); 535 } 536 componentPeer = null; 537 nativePeer = null; 538 539 synchronized (this) { 540 if (isDraggingInside) { 541 dragExit(new DropTargetEvent(getDropTargetContext())); 542 } 543 } 544 } 545 546 /** 547 * Gets the <code>DropTargetContext</code> associated 548 * with this <code>DropTarget</code>. 549 * 550 * @return the <code>DropTargetContext</code> associated with this <code>DropTarget</code>. 551 */ 552 553 public DropTargetContext getDropTargetContext() { 554 return dropTargetContext; 555 } 556 557 /** 558 * Creates the DropTargetContext associated with this DropTarget. 559 * Subclasses may override this method to instantiate their own 560 * DropTargetContext subclass. 561 * 562 * This call is typically *only* called by the platform's 563 * DropTargetContextPeer as a drag operation encounters this 564 * DropTarget. Accessing the Context while no Drag is current 565 * has undefined results. 566 * @return the DropTargetContext associated with this DropTarget 567 */ 568 569 protected DropTargetContext createDropTargetContext() { 570 return new DropTargetContext(this); 571 } 572 573 /** 574 * Serializes this <code>DropTarget</code>. Performs default serialization, 575 * and then writes out this object's <code>DropTargetListener</code> if and 576 * only if it can be serialized. If not, <code>null</code> is written 577 * instead. 578 * 579 * @serialData The default serializable fields, in alphabetical order, 580 * followed by either a <code>DropTargetListener</code> 581 * instance, or <code>null</code>. 582 * @since 1.4 583 */ 584 private void writeObject(ObjectOutputStream s) throws IOException { 585 s.defaultWriteObject(); 586 587 s.writeObject(SerializationTester.test(dtListener) 588 ? dtListener : null); 589 } 590 591 /** 592 * Deserializes this <code>DropTarget</code>. This method first performs 593 * default deserialization for all non-<code>transient</code> fields. An 594 * attempt is then made to deserialize this object's 595 * <code>DropTargetListener</code> as well. This is first attempted by 596 * deserializing the field <code>dtListener</code>, because, in releases 597 * prior to 1.4, a non-<code>transient</code> field of this name stored the 598 * <code>DropTargetListener</code>. If this fails, the next object in the 599 * stream is used instead. 600 * 601 * @since 1.4 602 */ 603 private void readObject(ObjectInputStream s) 604 throws ClassNotFoundException, IOException 605 { 606 ObjectInputStream.GetField f = s.readFields(); 607 608 try { 609 dropTargetContext = 610 (DropTargetContext)f.get("dropTargetContext", null); 611 } catch (IllegalArgumentException e) { 612 // Pre-1.4 support. 'dropTargetContext' was previously transient 613 } 614 if (dropTargetContext == null) { 615 dropTargetContext = createDropTargetContext(); 616 } 617 618 component = (Component)f.get("component", null); 619 actions = f.get("actions", DnDConstants.ACTION_COPY_OR_MOVE); 620 active = f.get("active", true); 621 622 // Pre-1.4 support. 'dtListener' was previously non-transient 623 try { 624 dtListener = (DropTargetListener)f.get("dtListener", null); 625 } catch (IllegalArgumentException e) { 626 // 1.4-compatible byte stream. 'dtListener' was written explicitly 627 dtListener = (DropTargetListener)s.readObject(); 628 } 629 } 630 631 /*********************************************************************/ 632 633 /** 634 * this protected nested class implements autoscrolling 635 */ 636 637 protected static class DropTargetAutoScroller implements ActionListener { 638 639 /** 640 * construct a DropTargetAutoScroller 641 * 642 * @param c the <code>Component</code> 643 * @param p the <code>Point</code> 644 */ 645 646 protected DropTargetAutoScroller(Component c, Point p) { 647 super(); 648 649 component = c; 650 autoScroll = (Autoscroll)component; 651 652 Toolkit t = Toolkit.getDefaultToolkit(); 653 654 Integer initial = Integer.valueOf(100); 655 Integer interval = Integer.valueOf(100); 656 657 try { 658 initial = (Integer)t.getDesktopProperty("DnD.Autoscroll.initialDelay"); 659 } catch (Exception e) { 660 // ignore 661 } 662 663 try { 664 interval = (Integer)t.getDesktopProperty("DnD.Autoscroll.interval"); 665 } catch (Exception e) { 666 // ignore 667 } 668 669 timer = new Timer(interval.intValue(), this); 670 671 timer.setCoalesce(true); 672 timer.setInitialDelay(initial.intValue()); 673 674 locn = p; 675 prev = p; 676 677 try { 678 hysteresis = ((Integer)t.getDesktopProperty("DnD.Autoscroll.cursorHysteresis")).intValue(); 679 } catch (Exception e) { 680 // ignore 681 } 682 683 timer.start(); 684 } 685 686 /** 687 * update the geometry of the autoscroll region 688 */ 689 690 @SuppressWarnings("deprecation") 691 private void updateRegion() { 692 Insets i = autoScroll.getAutoscrollInsets(); 693 Dimension size = component.getSize(); 694 695 if (size.width != outer.width || size.height != outer.height) 696 outer.reshape(0, 0, size.width, size.height); 697 698 if (inner.x != i.left || inner.y != i.top) 699 inner.setLocation(i.left, i.top); 700 701 int newWidth = size.width - (i.left + i.right); 702 int newHeight = size.height - (i.top + i.bottom); 703 704 if (newWidth != inner.width || newHeight != inner.height) 705 inner.setSize(newWidth, newHeight); 706 707 } 708 709 /** 710 * cause autoscroll to occur 711 * 712 * @param newLocn the <code>Point</code> 713 */ 714 715 protected synchronized void updateLocation(Point newLocn) { 716 prev = locn; 717 locn = newLocn; 718 719 if (Math.abs(locn.x - prev.x) > hysteresis || 720 Math.abs(locn.y - prev.y) > hysteresis) { 721 if (timer.isRunning()) timer.stop(); 722 } else { 723 if (!timer.isRunning()) timer.start(); 724 } 725 } 726 727 /** 728 * cause autoscrolling to stop 729 */ 730 731 protected void stop() { timer.stop(); } 732 733 /** 734 * cause autoscroll to occur 735 * 736 * @param e the <code>ActionEvent</code> 737 */ 738 739 public synchronized void actionPerformed(ActionEvent e) { 740 updateRegion(); 741 742 if (outer.contains(locn) && !inner.contains(locn)) 743 autoScroll.autoscroll(locn); 744 } 745 746 /* 747 * fields 748 */ 749 750 private Component component; 751 private Autoscroll autoScroll; 752 753 private Timer timer; 754 755 private Point locn; 756 private Point prev; 757 758 private Rectangle outer = new Rectangle(); 759 private Rectangle inner = new Rectangle(); 760 761 private int hysteresis = 10; 762 } 763 764 /*********************************************************************/ 765 766 /** 767 * create an embedded autoscroller 768 * 769 * @param c the <code>Component</code> 770 * @param p the <code>Point</code> 771 * @return an embedded autoscroller 772 */ 773 774 protected DropTargetAutoScroller createDropTargetAutoScroller(Component c, Point p) { 775 return new DropTargetAutoScroller(c, p); 776 } 777 778 /** 779 * initialize autoscrolling 780 * 781 * @param p the <code>Point</code> 782 */ 783 784 protected void initializeAutoscrolling(Point p) { 785 if (component == null || !(component instanceof Autoscroll)) return; 786 787 autoScroller = createDropTargetAutoScroller(component, p); 788 } 789 790 /** 791 * update autoscrolling with current cursor location 792 * 793 * @param dragCursorLocn the <code>Point</code> 794 */ 795 796 protected void updateAutoscroll(Point dragCursorLocn) { 797 if (autoScroller != null) autoScroller.updateLocation(dragCursorLocn); 798 } 799 800 /** 801 * clear autoscrolling 802 */ 803 804 protected void clearAutoscroll() { 805 if (autoScroller != null) { 806 autoScroller.stop(); 807 autoScroller = null; 808 } 809 } 810 811 /** 812 * The DropTargetContext associated with this DropTarget. 813 * 814 * @serial 815 */ 816 private DropTargetContext dropTargetContext = createDropTargetContext(); 817 818 /** 819 * The Component associated with this DropTarget. 820 * 821 * @serial 822 */ 823 private Component component; 824 825 /* 826 * That Component's Peer 827 */ 828 private transient ComponentPeer componentPeer; 829 830 /* 831 * That Component's "native" Peer 832 */ 833 private transient DropTargetPeer nativePeer; 834 835 836 /** 837 * Default permissible actions supported by this DropTarget. 838 * 839 * @see #setDefaultActions 840 * @see #getDefaultActions 841 * @serial 842 */ 843 int actions = DnDConstants.ACTION_COPY_OR_MOVE; 844 845 /** 846 * <code>true</code> if the DropTarget is accepting Drag & Drop operations. 847 * 848 * @serial 849 */ 850 boolean active = true; 851 852 /* 853 * the auto scrolling object 854 */ 855 856 private transient DropTargetAutoScroller autoScroller; 857 858 /* 859 * The delegate 860 */ 861 862 private transient DropTargetListener dtListener; 863 864 /* 865 * The FlavorMap 866 */ 867 868 private transient FlavorMap flavorMap; 869 870 /* 871 * If the dragging is currently inside this drop target 872 */ 873 private transient boolean isDraggingInside; 874 }