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