View Javadoc
1   /*
2    * Copyright (c) 1997, 2013, 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.
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      * @see java.awt.dnd.DnDConstants
250      */
251 
252     public void setDefaultActions(int ops) {
253         getDropTargetContext().setTargetActions(ops & (DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_REFERENCE));
254     }
255 
256     /*
257      * Called by DropTargetContext.setTargetActions()
258      * with appropriate synchronization.
259      */
260     void doSetDefaultActions(int ops) {
261         actions = ops;
262     }
263 
264     /**
265      * Gets an <code>int</code> representing the
266      * current action(s) supported by this <code>DropTarget</code>.
267      * <P>
268      * @return the current default actions
269      */
270 
271     public int getDefaultActions() {
272         return actions;
273     }
274 
275     /**
276      * Sets the DropTarget active if <code>true</code>,
277      * inactive if <code>false</code>.
278      * <P>
279      * @param isActive sets the <code>DropTarget</code> (in)active.
280      */
281 
282     public synchronized void setActive(boolean isActive) {
283         if (isActive != active) {
284             active = isActive;
285         }
286 
287         if (!active) clearAutoscroll();
288     }
289 
290     /**
291      * Reports whether or not
292      * this <code>DropTarget</code>
293      * is currently active (ready to accept drops).
294      * <P>
295      * @return <CODE>true</CODE> if active, <CODE>false</CODE> if not
296      */
297 
298     public boolean isActive() {
299         return active;
300     }
301 
302     /**
303      * Adds a new <code>DropTargetListener</code> (UNICAST SOURCE).
304      * <P>
305      * @param dtl The new <code>DropTargetListener</code>
306      * <P>
307      * @throws TooManyListenersException if a
308      * <code>DropTargetListener</code> is already added to this
309      * <code>DropTarget</code>.
310      */
311 
312     public synchronized void addDropTargetListener(DropTargetListener dtl) throws TooManyListenersException {
313         if (dtl == null) return;
314 
315         if (equals(dtl)) throw new IllegalArgumentException("DropTarget may not be its own Listener");
316 
317         if (dtListener == null)
318             dtListener = dtl;
319         else
320             throw new TooManyListenersException();
321     }
322 
323     /**
324      * Removes the current <code>DropTargetListener</code> (UNICAST SOURCE).
325      * <P>
326      * @param dtl the DropTargetListener to deregister.
327      */
328 
329     public synchronized void removeDropTargetListener(DropTargetListener dtl) {
330         if (dtl != null && dtListener != null) {
331             if(dtListener.equals(dtl))
332                 dtListener = null;
333             else
334                 throw new IllegalArgumentException("listener mismatch");
335         }
336     }
337 
338     /**
339      * Calls <code>dragEnter</code> on the registered
340      * <code>DropTargetListener</code> and passes it
341      * the specified <code>DropTargetDragEvent</code>.
342      * Has no effect if this <code>DropTarget</code>
343      * is not active.
344      *
345      * @param dtde the <code>DropTargetDragEvent</code>
346      *
347      * @throws NullPointerException if this <code>DropTarget</code>
348      *         is active and <code>dtde</code> is <code>null</code>
349      *
350      * @see #isActive
351      */
352     public synchronized void dragEnter(DropTargetDragEvent dtde) {
353         isDraggingInside = true;
354 
355         if (!active) return;
356 
357         if (dtListener != null) {
358             dtListener.dragEnter(dtde);
359         } else
360             dtde.getDropTargetContext().setTargetActions(DnDConstants.ACTION_NONE);
361 
362         initializeAutoscrolling(dtde.getLocation());
363     }
364 
365     /**
366      * Calls <code>dragOver</code> on the registered
367      * <code>DropTargetListener</code> and passes it
368      * the specified <code>DropTargetDragEvent</code>.
369      * Has no effect if this <code>DropTarget</code>
370      * is not active.
371      *
372      * @param dtde the <code>DropTargetDragEvent</code>
373      *
374      * @throws NullPointerException if this <code>DropTarget</code>
375      *         is active and <code>dtde</code> is <code>null</code>
376      *
377      * @see #isActive
378      */
379     public synchronized void dragOver(DropTargetDragEvent dtde) {
380         if (!active) return;
381 
382         if (dtListener != null && active) dtListener.dragOver(dtde);
383 
384         updateAutoscroll(dtde.getLocation());
385     }
386 
387     /**
388      * Calls <code>dropActionChanged</code> on the registered
389      * <code>DropTargetListener</code> and passes it
390      * the specified <code>DropTargetDragEvent</code>.
391      * Has no effect if this <code>DropTarget</code>
392      * is not active.
393      *
394      * @param dtde the <code>DropTargetDragEvent</code>
395      *
396      * @throws NullPointerException if this <code>DropTarget</code>
397      *         is active and <code>dtde</code> is <code>null</code>
398      *
399      * @see #isActive
400      */
401     public synchronized void dropActionChanged(DropTargetDragEvent dtde) {
402         if (!active) return;
403 
404         if (dtListener != null) dtListener.dropActionChanged(dtde);
405 
406         updateAutoscroll(dtde.getLocation());
407     }
408 
409     /**
410      * Calls <code>dragExit</code> on the registered
411      * <code>DropTargetListener</code> and passes it
412      * the specified <code>DropTargetEvent</code>.
413      * Has no effect if this <code>DropTarget</code>
414      * is not active.
415      * <p>
416      * This method itself does not throw any exception
417      * for null parameter but for exceptions thrown by
418      * the respective method of the listener.
419      *
420      * @param dte the <code>DropTargetEvent</code>
421      *
422      * @see #isActive
423      */
424     public synchronized void dragExit(DropTargetEvent dte) {
425         isDraggingInside = false;
426 
427         if (!active) return;
428 
429         if (dtListener != null && active) dtListener.dragExit(dte);
430 
431         clearAutoscroll();
432     }
433 
434     /**
435      * Calls <code>drop</code> on the registered
436      * <code>DropTargetListener</code> and passes it
437      * the specified <code>DropTargetDropEvent</code>
438      * if this <code>DropTarget</code> is active.
439      *
440      * @param dtde the <code>DropTargetDropEvent</code>
441      *
442      * @throws NullPointerException if <code>dtde</code> is null
443      *         and at least one of the following is true: this
444      *         <code>DropTarget</code> is not active, or there is
445      *         no a <code>DropTargetListener</code> registered.
446      *
447      * @see #isActive
448      */
449     public synchronized void drop(DropTargetDropEvent dtde) {
450         isDraggingInside = false;
451 
452         clearAutoscroll();
453 
454         if (dtListener != null && active)
455             dtListener.drop(dtde);
456         else { // we should'nt get here ...
457             dtde.rejectDrop();
458         }
459     }
460 
461     /**
462      * Gets the <code>FlavorMap</code>
463      * associated with this <code>DropTarget</code>.
464      * If no <code>FlavorMap</code> has been set for this
465      * <code>DropTarget</code>, it is associated with the default
466      * <code>FlavorMap</code>.
467      * <P>
468      * @return the FlavorMap for this DropTarget
469      */
470 
471     public FlavorMap getFlavorMap() { return flavorMap; }
472 
473     /**
474      * Sets the <code>FlavorMap</code> associated
475      * with this <code>DropTarget</code>.
476      * <P>
477      * @param fm the new <code>FlavorMap</code>, or null to
478      * associate the default FlavorMap with this DropTarget.
479      */
480 
481     public void setFlavorMap(FlavorMap fm) {
482         flavorMap = fm == null ? SystemFlavorMap.getDefaultFlavorMap() : fm;
483     }
484 
485     /**
486      * Notify the DropTarget that it has been associated with a Component
487      *
488      **********************************************************************
489      * This method is usually called from java.awt.Component.addNotify() of
490      * the Component associated with this DropTarget to notify the DropTarget
491      * that a ComponentPeer has been associated with that Component.
492      *
493      * Calling this method, other than to notify this DropTarget of the
494      * association of the ComponentPeer with the Component may result in
495      * a malfunction of the DnD system.
496      **********************************************************************
497      * <P>
498      * @param peer The Peer of the Component we are associated with!
499      *
500      */
501 
502     public void addNotify(ComponentPeer peer) {
503         if (peer == componentPeer) return;
504 
505         componentPeer = peer;
506 
507         for (Component c = component;
508              c != null && peer instanceof LightweightPeer; c = c.getParent()) {
509             peer = c.getPeer();
510         }
511 
512         if (peer instanceof DropTargetPeer) {
513             nativePeer = peer;
514             ((DropTargetPeer)peer).addDropTarget(this);
515         } else {
516             nativePeer = null;
517         }
518     }
519 
520     /**
521      * Notify the DropTarget that it has been disassociated from a Component
522      *
523      **********************************************************************
524      * This method is usually called from java.awt.Component.removeNotify() of
525      * the Component associated with this DropTarget to notify the DropTarget
526      * that a ComponentPeer has been disassociated with that Component.
527      *
528      * Calling this method, other than to notify this DropTarget of the
529      * disassociation of the ComponentPeer from the Component may result in
530      * a malfunction of the DnD system.
531      **********************************************************************
532      * <P>
533      * @param peer The Peer of the Component we are being disassociated from!
534      */
535 
536     public void removeNotify(ComponentPeer peer) {
537         if (nativePeer != null)
538             ((DropTargetPeer)nativePeer).removeDropTarget(this);
539 
540         componentPeer = nativePeer = null;
541 
542         synchronized (this) {
543             if (isDraggingInside) {
544                 dragExit(new DropTargetEvent(getDropTargetContext()));
545             }
546         }
547     }
548 
549     /**
550      * Gets the <code>DropTargetContext</code> associated
551      * with this <code>DropTarget</code>.
552      * <P>
553      * @return the <code>DropTargetContext</code> associated with this <code>DropTarget</code>.
554      */
555 
556     public DropTargetContext getDropTargetContext() {
557         return dropTargetContext;
558     }
559 
560     /**
561      * Creates the DropTargetContext associated with this DropTarget.
562      * Subclasses may override this method to instantiate their own
563      * DropTargetContext subclass.
564      *
565      * This call is typically *only* called by the platform's
566      * DropTargetContextPeer as a drag operation encounters this
567      * DropTarget. Accessing the Context while no Drag is current
568      * has undefined results.
569      */
570 
571     protected DropTargetContext createDropTargetContext() {
572         return new DropTargetContext(this);
573     }
574 
575     /**
576      * Serializes this <code>DropTarget</code>. Performs default serialization,
577      * and then writes out this object's <code>DropTargetListener</code> if and
578      * only if it can be serialized. If not, <code>null</code> is written
579      * instead.
580      *
581      * @serialData The default serializable fields, in alphabetical order,
582      *             followed by either a <code>DropTargetListener</code>
583      *             instance, or <code>null</code>.
584      * @since 1.4
585      */
586     private void writeObject(ObjectOutputStream s) throws IOException {
587         s.defaultWriteObject();
588 
589         s.writeObject(SerializationTester.test(dtListener)
590                       ? dtListener : null);
591     }
592 
593     /**
594      * Deserializes this <code>DropTarget</code>. This method first performs
595      * default deserialization for all non-<code>transient</code> fields. An
596      * attempt is then made to deserialize this object's
597      * <code>DropTargetListener</code> as well. This is first attempted by
598      * deserializing the field <code>dtListener</code>, because, in releases
599      * prior to 1.4, a non-<code>transient</code> field of this name stored the
600      * <code>DropTargetListener</code>. If this fails, the next object in the
601      * stream is used instead.
602      *
603      * @since 1.4
604      */
605     private void readObject(ObjectInputStream s)
606         throws ClassNotFoundException, IOException
607     {
608         ObjectInputStream.GetField f = s.readFields();
609 
610         try {
611             dropTargetContext =
612                 (DropTargetContext)f.get("dropTargetContext", null);
613         } catch (IllegalArgumentException e) {
614             // Pre-1.4 support. 'dropTargetContext' was previously transient
615         }
616         if (dropTargetContext == null) {
617             dropTargetContext = createDropTargetContext();
618         }
619 
620         component = (Component)f.get("component", null);
621         actions = f.get("actions", DnDConstants.ACTION_COPY_OR_MOVE);
622         active = f.get("active", true);
623 
624         // Pre-1.4 support. 'dtListener' was previously non-transient
625         try {
626             dtListener = (DropTargetListener)f.get("dtListener", null);
627         } catch (IllegalArgumentException e) {
628             // 1.4-compatible byte stream. 'dtListener' was written explicitly
629             dtListener = (DropTargetListener)s.readObject();
630         }
631     }
632 
633     /*********************************************************************/
634 
635     /**
636      * this protected nested class implements autoscrolling
637      */
638 
639     protected static class DropTargetAutoScroller implements ActionListener {
640 
641         /**
642          * construct a DropTargetAutoScroller
643          * <P>
644          * @param c the <code>Component</code>
645          * @param p the <code>Point</code>
646          */
647 
648         protected DropTargetAutoScroller(Component c, Point p) {
649             super();
650 
651             component  = c;
652             autoScroll = (Autoscroll)component;
653 
654             Toolkit t  = Toolkit.getDefaultToolkit();
655 
656             Integer    initial  = Integer.valueOf(100);
657             Integer    interval = Integer.valueOf(100);
658 
659             try {
660                 initial = (Integer)t.getDesktopProperty("DnD.Autoscroll.initialDelay");
661             } catch (Exception e) {
662                 // ignore
663             }
664 
665             try {
666                 interval = (Integer)t.getDesktopProperty("DnD.Autoscroll.interval");
667             } catch (Exception e) {
668                 // ignore
669             }
670 
671             timer  = new Timer(interval.intValue(), this);
672 
673             timer.setCoalesce(true);
674             timer.setInitialDelay(initial.intValue());
675 
676             locn = p;
677             prev = p;
678 
679             try {
680                 hysteresis = ((Integer)t.getDesktopProperty("DnD.Autoscroll.cursorHysteresis")).intValue();
681             } catch (Exception e) {
682                 // ignore
683             }
684 
685             timer.start();
686         }
687 
688         /**
689          * update the geometry of the autoscroll region
690          */
691 
692         private void updateRegion() {
693            Insets    i    = autoScroll.getAutoscrollInsets();
694            Dimension size = component.getSize();
695 
696            if (size.width != outer.width || size.height != outer.height)
697                 outer.reshape(0, 0, size.width, size.height);
698 
699            if (inner.x != i.left || inner.y != i.top)
700                 inner.setLocation(i.left, i.top);
701 
702            int newWidth  = size.width -  (i.left + i.right);
703            int newHeight = size.height - (i.top  + i.bottom);
704 
705            if (newWidth != inner.width || newHeight != inner.height)
706                 inner.setSize(newWidth, newHeight);
707 
708         }
709 
710         /**
711          * cause autoscroll to occur
712          * <P>
713          * @param newLocn the <code>Point</code>
714          */
715 
716         protected synchronized void updateLocation(Point newLocn) {
717             prev = locn;
718             locn = newLocn;
719 
720             if (Math.abs(locn.x - prev.x) > hysteresis ||
721                 Math.abs(locn.y - prev.y) > hysteresis) {
722                 if (timer.isRunning()) timer.stop();
723             } else {
724                 if (!timer.isRunning()) timer.start();
725             }
726         }
727 
728         /**
729          * cause autoscrolling to stop
730          */
731 
732         protected void stop() { timer.stop(); }
733 
734         /**
735          * cause autoscroll to occur
736          * <P>
737          * @param e the <code>ActionEvent</code>
738          */
739 
740         public synchronized void actionPerformed(ActionEvent e) {
741             updateRegion();
742 
743             if (outer.contains(locn) && !inner.contains(locn))
744                 autoScroll.autoscroll(locn);
745         }
746 
747         /*
748          * fields
749          */
750 
751         private Component  component;
752         private Autoscroll autoScroll;
753 
754         private Timer      timer;
755 
756         private Point      locn;
757         private Point      prev;
758 
759         private Rectangle  outer = new Rectangle();
760         private Rectangle  inner = new Rectangle();
761 
762         private int        hysteresis = 10;
763     }
764 
765     /*********************************************************************/
766 
767     /**
768      * create an embedded autoscroller
769      * <P>
770      * @param c the <code>Component</code>
771      * @param p the <code>Point</code>
772      */
773 
774     protected DropTargetAutoScroller createDropTargetAutoScroller(Component c, Point p) {
775         return new DropTargetAutoScroller(c, p);
776     }
777 
778     /**
779      * initialize autoscrolling
780      * <P>
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      * <P>
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 ComponentPeer 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 &amp; 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 }