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