KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > awt > dnd > DragSourceContext


1 /*
2  * @(#)DragSourceContext.java 1.51 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.awt.dnd;
9
10 import java.awt.event.InputEvent JavaDoc;
11 import java.awt.Component JavaDoc;
12 import java.awt.Cursor JavaDoc;
13 import java.awt.Image JavaDoc;
14 import java.awt.Point JavaDoc;
15
16 import java.awt.datatransfer.DataFlavor JavaDoc;
17 import java.awt.datatransfer.Transferable JavaDoc;
18 import java.awt.datatransfer.UnsupportedFlavorException JavaDoc;
19
20 import java.awt.dnd.DragGestureEvent JavaDoc;
21 import java.awt.dnd.DragSource JavaDoc;
22 import java.awt.dnd.DragSourceListener JavaDoc;
23 import java.awt.dnd.InvalidDnDOperationException JavaDoc;
24
25 import java.awt.dnd.peer.DragSourceContextPeer;
26
27 import java.io.IOException JavaDoc;
28 import java.io.ObjectOutputStream JavaDoc;
29 import java.io.ObjectInputStream JavaDoc;
30 import java.io.Serializable JavaDoc;
31
32 import java.util.TooManyListenersException JavaDoc;
33
34 /**
35  * The <code>DragSourceContext</code> class is responsible for managing the
36  * initiator side of the Drag and Drop protocol. In particular, it is responsible
37  * for managing drag event notifications to the <code>DragSourceListener</code>s
38  * and <code>DragSourceMotionListener</code>s, and providing the
39  * <code>Transferable</code> representing the source data for the drag operation.
40  * <p>
41  * Note that the <code>DragSourceContext</code> itself
42  * implements the <code>DragSourceListener</code> and
43  * <code>DragSourceMotionListener</code> interfaces.
44  * This is to allow the platform peer
45  * (the <code>DragSourceContextPeer</code> instance)
46  * created by the <code>DragSource</code> to notify
47  * the <code>DragSourceContext</code> of
48  * state changes in the ongoing operation. This allows the
49  * <code>DragSourceContext</code> to interpose
50  * itself between the platform and the
51  * listeners provided by the initiator of the drag operation.
52  *
53  * @see DragSourceListener
54  * @see DragSourceMotionListener
55  * @version 1.51, 12/19/03
56  * @since 1.2
57  */

58
59 public class DragSourceContext
60     implements DragSourceListener JavaDoc, DragSourceMotionListener JavaDoc, Serializable JavaDoc {
61
62     private static final long serialVersionUID = -115407898692194719L;
63
64     // used by updateCurrentCursor
65

66     /**
67      * An <code>int</code> used by updateCurrentCursor()
68      * indicating that the <code>Cursor</code> should change
69      * to the default (no drop) <code>Cursor</code>.
70      */

71     protected static final int DEFAULT = 0;
72
73     /**
74      * An <code>int</code> used by updateCurrentCursor()
75      * indicating that the <code>Cursor</code>
76      * has entered a <code>DropTarget</code>.
77      */

78     protected static final int ENTER = 1;
79
80     /**
81      * An <code>int</code> used by updateCurrentCursor()
82      * indicating that the <code>Cursor</code> is
83      * over a <code>DropTarget</code>.
84      */

85     protected static final int OVER = 2;
86
87     /**
88      * An <code>int</code> used by updateCurrentCursor()
89      * indicating that the user operation has changed.
90      */

91
92     protected static final int CHANGED = 3;
93     
94     /**
95      * Called from <code>DragSource</code>, this constructor creates a new
96      * <code>DragSourceContext</code> given the
97      * <code>DragSourceContextPeer</code> for this Drag, the
98      * <code>DragGestureEvent</code> that triggered the Drag, the initial
99      * <code>Cursor</code> to use for the Drag, an (optional)
100      * <code>Image</code> to display while the Drag is taking place, the offset
101      * of the <code>Image</code> origin from the hotspot at the instant of the
102      * triggering event, the <code>Transferable</code> subject data, and the
103      * <code>DragSourceListener</code> to use during the Drag and Drop
104      * operation.
105      * <br>
106      * If <code>DragSourceContextPeer</code> is <code>null</code>
107      * <code>NullPointerException</code> is thrown.
108      * <br>
109      * If <code>DragGestureEvent</code> is <code>null</code>
110      * <code>NullPointerException</code> is thrown.
111      * <br>
112      * If <code>Cursor</code> is <code>null</code> no exception is thrown and
113      * the default drag cursor behavior is activated for this drag operation.
114      * <br>
115      * If <code>Image</code> is <code>null</code> no exception is thrown.
116      * <br>
117      * If <code>Image</code> is not <code>null</code> and the offset is
118      * <code>null</code> <code>NullPointerException</code> is thrown.
119      * <br>
120      * If <code>Transferable</code> is <code>null</code>
121      * <code>NullPointerException</code> is thrown.
122      * <br>
123      * If <code>DragSourceListener</code> is <code>null</code> no exception
124      * is thrown.
125      *
126      * @param dscp the <code>DragSourceContextPeer</code> for this drag
127      * @param trigger the triggering event
128      * @param dragCursor the initial <code>Cursor</code>
129      * @param dragImage the <code>Image</code> to drag (or <code>null</code>)
130      * @param offset the offset of the image origin from the hotspot at the
131      * instant of the triggering event
132      * @param t the <code>Transferable</code>
133      * @param dsl the <code>DragSourceListener</code>
134      *
135      * @throws IllegalArgumentException if the <code>Component</code> associated
136      * with the trigger event is <code>null</code>.
137      * @throws IllegalArgumentException if the <code>DragSource</code> for the
138      * trigger event is <code>null</code>.
139      * @throws IllegalArgumentException if the drag action for the
140      * trigger event is <code>DnDConstants.ACTION_NONE</code>.
141      * @throws IllegalArgumentException if the source actions for the
142      * <code>DragGestureRecognizer</code> associated with the trigger
143      * event are equal to <code>DnDConstants.ACTION_NONE</code>.
144      * @throws NullPointerException if dscp, trigger, or t are null, or
145      * if dragImage is non-null and offset is null
146      */

147     public DragSourceContext(DragSourceContextPeer dscp,
148                              DragGestureEvent JavaDoc trigger, Cursor JavaDoc dragCursor,
149                              Image JavaDoc dragImage, Point JavaDoc offset, Transferable JavaDoc t,
150                              DragSourceListener JavaDoc dsl) {
151         if (dscp == null) {
152             throw new NullPointerException JavaDoc("DragSourceContextPeer");
153         }
154
155         if (trigger == null) {
156             throw new NullPointerException JavaDoc("Trigger");
157         }
158
159         if (trigger.getDragSource() == null) {
160             throw new IllegalArgumentException JavaDoc("DragSource");
161         }
162
163         if (trigger.getComponent() == null) {
164             throw new IllegalArgumentException JavaDoc("Component");
165         }
166
167         if (trigger.getSourceAsDragGestureRecognizer().getSourceActions() ==
168                  DnDConstants.ACTION_NONE) {
169             throw new IllegalArgumentException JavaDoc("source actions");
170         }
171
172         if (trigger.getDragAction() == DnDConstants.ACTION_NONE) {
173             throw new IllegalArgumentException JavaDoc("no drag action");
174         }
175
176         if (t == null) {
177             throw new NullPointerException JavaDoc("Transferable");
178         }
179
180         if (dragImage != null && offset == null) {
181             throw new NullPointerException JavaDoc("offset");
182         }
183     
184         peer = dscp;
185         this.trigger = trigger;
186         cursor = dragCursor;
187         transferable = t;
188         listener = dsl;
189         sourceActions =
190             trigger.getSourceAsDragGestureRecognizer().getSourceActions();
191
192         useCustomCursor = (dragCursor != null);
193
194         updateCurrentCursor(trigger.getDragAction(), getSourceActions(), DEFAULT);
195     }
196
197     /**
198      * Returns the <code>DragSource</code>
199      * that instantiated this <code>DragSourceContext</code>.
200      *
201      * @return the <code>DragSource</code> that
202      * instantiated this <code>DragSourceContext</code>
203      */

204
205     public DragSource JavaDoc getDragSource() { return trigger.getDragSource(); }
206
207     /**
208      * Returns the <code>Component</code> associated with this
209      * <code>DragSourceContext</code>.
210      *
211      * @return the <code>Component</code> that started the drag
212      */

213
214     public Component JavaDoc getComponent() { return trigger.getComponent(); }
215
216     /**
217      * Returns the <code>DragGestureEvent</code>
218      * that initially triggered the drag.
219      *
220      * @return the Event that triggered the drag
221      */

222
223     public DragGestureEvent JavaDoc getTrigger() { return trigger; }
224
225     /**
226      * Returns a bitwise mask of <code>DnDConstants</code> that
227      * represent the set of drop actions supported by the drag source for the
228      * drag operation associated with this <code>DragSourceContext</code>.
229      *
230      * @return the drop actions supported by the drag source
231      */

232     public int getSourceActions() {
233         return sourceActions;
234     }
235
236     /**
237      * Sets the cursor for this drag operation to the specified
238      * <code>Cursor</code>. If the specified <code>Cursor</code>
239      * is <code>null</code>, the default drag cursor behavior is
240      * activated for this drag operation, otherwise it is deactivated.
241      *
242      * @param c the <code>Cursor</code> to display, or
243      * <code>null</code> to activate the default drag cursor
244      * behavior
245      *
246      */

247
248     public synchronized void setCursor(Cursor JavaDoc c) {
249         useCustomCursor = (c != null);
250         setCursorImpl(c);
251     }
252
253     /**
254      * Returns the current drag <code>Cursor</code>.
255      * <P>
256      * @return the current drag <code>Cursor</code>
257      */

258
259     public Cursor JavaDoc getCursor() { return cursor; }
260
261     /**
262      * Add a <code>DragSourceListener</code> to this
263      * <code>DragSourceContext</code> if one has not already been added.
264      * If a <code>DragSourceListener</code> already exists,
265      * this method throws a <code>TooManyListenersException</code>.
266      * <P>
267      * @param dsl the <code>DragSourceListener</code> to add.
268      * Note that while <code>null</code> is not prohibited,
269      * it is not acceptable as a parameter.
270      * <P>
271      * @throws <code>TooManyListenersException</code> if
272      * a <code>DragSourceListener</code> has already been added
273      */

274
275     public synchronized void addDragSourceListener(DragSourceListener JavaDoc dsl) throws TooManyListenersException JavaDoc {
276     if (dsl == null) return;
277
278     if (equals(dsl)) throw new IllegalArgumentException JavaDoc("DragSourceContext may not be its own listener");
279
280     if (listener != null)
281         throw new TooManyListenersException JavaDoc();
282     else
283         listener = dsl;
284     }
285
286     /**
287      * Removes the specified <code>DragSourceListener</code>
288      * from this <code>DragSourceContext</code>.
289      *
290      * @param dsl the <code>DragSourceListener</code> to remove;
291      * note that while <code>null</code> is not prohibited,
292      * it is not acceptable as a parameter
293      */

294
295     public synchronized void removeDragSourceListener(DragSourceListener JavaDoc dsl) {
296     if (listener != null && listener.equals(dsl)) {
297         listener = null;
298     } else
299         throw new IllegalArgumentException JavaDoc();
300     }
301
302     /**
303      * Notifies the peer that the <code>Transferable</code>'s
304      * <code>DataFlavor</code>s have changed.
305      */

306
307     public void transferablesFlavorsChanged() {
308     if (peer != null) peer.transferablesFlavorsChanged();
309     }
310
311     /**
312      * Calls <code>dragEnter</code> on the
313      * <code>DragSourceListener</code>s registered with this
314      * <code>DragSourceContext</code> and with the associated
315      * <code>DragSource</code>, and passes them the specified
316      * <code>DragSourceDragEvent</code>.
317      *
318      * @param dsde the <code>DragSourceDragEvent</code>
319      */

320     public void dragEnter(DragSourceDragEvent JavaDoc dsde) {
321         DragSourceListener JavaDoc dsl = listener;
322         if (dsl != null) {
323             dsl.dragEnter(dsde);
324         }
325         getDragSource().processDragEnter(dsde);
326
327     updateCurrentCursor(dsde.getDropAction(), dsde.getTargetActions(), ENTER);
328     }
329
330     /**
331      * Calls <code>dragOver</code> on the
332      * <code>DragSourceListener</code>s registered with this
333      * <code>DragSourceContext</code> and with the associated
334      * <code>DragSource</code>, and passes them the specified
335      * <code>DragSourceDragEvent</code>.
336      *
337      * @param dsde the <code>DragSourceDragEvent</code>
338      */

339     public void dragOver(DragSourceDragEvent JavaDoc dsde) {
340         DragSourceListener JavaDoc dsl = listener;
341         if (dsl != null) {
342             dsl.dragOver(dsde);
343         }
344         getDragSource().processDragOver(dsde);
345
346     updateCurrentCursor(dsde.getDropAction(), dsde.getTargetActions(), OVER);
347     }
348
349     /**
350      * Calls <code>dragExit</code> on the
351      * <code>DragSourceListener</code>s registered with this
352      * <code>DragSourceContext</code> and with the associated
353      * <code>DragSource</code>, and passes them the specified
354      * <code>DragSourceEvent</code>.
355      *
356      * @param dse the <code>DragSourceEvent</code>
357      */

358     public void dragExit(DragSourceEvent JavaDoc dse) {
359         DragSourceListener JavaDoc dsl = listener;
360         if (dsl != null) {
361             dsl.dragExit(dse);
362         }
363         getDragSource().processDragExit(dse);
364
365     updateCurrentCursor(DnDConstants.ACTION_NONE, DnDConstants.ACTION_NONE, DEFAULT);
366     }
367
368     /**
369      * Calls <code>dropActionChanged</code> on the
370      * <code>DragSourceListener</code>s registered with this
371      * <code>DragSourceContext</code> and with the associated
372      * <code>DragSource</code>, and passes them the specified
373      * <code>DragSourceDragEvent</code>.
374      *
375      * @param dsde the <code>DragSourceDragEvent</code>
376      */

377     public void dropActionChanged(DragSourceDragEvent JavaDoc dsde) {
378         DragSourceListener JavaDoc dsl = listener;
379         if (dsl != null) {
380             dsl.dropActionChanged(dsde);
381         }
382         getDragSource().processDropActionChanged(dsde);
383
384     updateCurrentCursor(dsde.getDropAction(), dsde.getTargetActions(), CHANGED);
385     }
386
387     /**
388      * Calls <code>dragDropEnd</code> on the
389      * <code>DragSourceListener</code>s registered with this
390      * <code>DragSourceContext</code> and with the associated
391      * <code>DragSource</code>, and passes them the specified
392      * <code>DragSourceDropEvent</code>.
393      *
394      * @param dsde the <code>DragSourceDropEvent</code>
395      */

396     public void dragDropEnd(DragSourceDropEvent JavaDoc dsde) {
397         DragSourceListener JavaDoc dsl = listener;
398         if (dsl != null) {
399             dsl.dragDropEnd(dsde);
400         }
401         getDragSource().processDragDropEnd(dsde);
402     }
403
404     /**
405      * Calls <code>dragMouseMoved</code> on the
406      * <code>DragSourceMotionListener</code>s registered with the
407      * <code>DragSource</code> associated with this
408      * <code>DragSourceContext</code>, and them passes the specified
409      * <code>DragSourceDragEvent</code>.
410      *
411      * @param dsde the <code>DragSourceDragEvent</code>
412      * @since 1.4
413      */

414     public void dragMouseMoved(DragSourceDragEvent JavaDoc dsde) {
415         getDragSource().processDragMouseMoved(dsde);
416     }
417
418     /**
419      * Returns the <code>Transferable</code> associated with
420      * this <code>DragSourceContext</code>.
421      *
422      * @return the <code>Transferable</code>
423      */

424     public Transferable JavaDoc getTransferable() { return transferable; }
425    
426     /**
427      * If the default drag cursor behavior is active, this method
428      * sets the default drag cursor for the specified selected
429      * operation, supported actions and status, otherwise this
430      * method does nothing.
431      *
432      * @param dropOp the user's currently selected operation
433      * @param targetAct the current target's supported actions
434      * @param status the constant
435      */

436
437     protected synchronized void updateCurrentCursor(int dropOp, int targetAct, int status) {
438
439     // if the cursor has been previously set then dont do any defaults
440
// processing.
441

442     if (useCustomCursor) {
443         return;
444     }
445
446     // do defaults processing
447

448     Cursor JavaDoc c = null;
449
450     switch (status) {
451         default:
452         targetAct = DnDConstants.ACTION_NONE;
453         case ENTER:
454         case OVER:
455         case CHANGED:
456         int ra = dropOp & targetAct;
457
458         if (ra == DnDConstants.ACTION_NONE) { // no drop possible
459
if ((dropOp & DnDConstants.ACTION_LINK) == DnDConstants.ACTION_LINK)
460                 c = DragSource.DefaultLinkNoDrop;
461             else if ((dropOp & DnDConstants.ACTION_MOVE) == DnDConstants.ACTION_MOVE)
462                 c = DragSource.DefaultMoveNoDrop;
463             else
464                 c = DragSource.DefaultCopyNoDrop;
465         } else { // drop possible
466
if ((ra & DnDConstants.ACTION_LINK) == DnDConstants.ACTION_LINK)
467                 c = DragSource.DefaultLinkDrop;
468             else if ((ra & DnDConstants.ACTION_MOVE) == DnDConstants.ACTION_MOVE)
469                 c = DragSource.DefaultMoveDrop;
470             else
471                 c = DragSource.DefaultCopyDrop;
472         }
473     }
474
475         setCursorImpl(c);
476     }
477
478     private void setCursorImpl(Cursor JavaDoc c) {
479         if (cursor == null || !cursor.equals(c)) {
480             cursor = c;
481             if (peer != null) peer.setCursor(cursor);
482         }
483     }
484
485     /**
486      * Serializes this <code>DragSourceContext</code>. This method first
487      * performs default serialization. Next, this object's
488      * <code>Transferable</code> is written out if and only if it can be
489      * serialized. If not, <code>null</code> is written instead. In this case,
490      * a <code>DragSourceContext</code> created from the resulting deserialized
491      * stream will contain a dummy <code>Transferable</code> which supports no
492      * <code>DataFlavor</code>s. Finally, this object's
493      * <code>DragSourceListener</code> is written out if and only if it can be
494      * serialized. If not, <code>null</code> is written instead.
495      *
496      * @serialData The default serializable fields, in alphabetical order,
497      * followed by either a <code>Transferable</code> instance, or
498      * <code>null</code>, followed by either a
499      * <code>DragSourceListener</code> instance, or
500      * <code>null</code>.
501      * @since 1.4
502      */

503     private void writeObject(ObjectOutputStream JavaDoc s) throws IOException JavaDoc {
504         s.defaultWriteObject();
505
506         s.writeObject(SerializationTester.test(transferable)
507                       ? transferable : null);
508         s.writeObject(SerializationTester.test(listener)
509                       ? listener : null);
510     }
511
512     /**
513      * Deserializes this <code>DragSourceContext</code>. This method first
514      * performs default deserialization for all non-<code>transient</code>
515      * fields. This object's <code>Transferable</code> and
516      * <code>DragSourceListener</code> are then deserialized as well by using
517      * the next two objects in the stream. If the resulting
518      * <code>Transferable</code> is <code>null</code>, this object's
519      * <code>Transferable</code> is set to a dummy <code>Transferable</code>
520      * which supports no <code>DataFlavor</code>s.
521      *
522      * @since 1.4
523      */

524     private void readObject(ObjectInputStream JavaDoc s)
525         throws ClassNotFoundException JavaDoc, IOException JavaDoc
526     {
527         s.defaultReadObject();
528
529         transferable = (Transferable JavaDoc)s.readObject();
530         listener = (DragSourceListener JavaDoc)s.readObject();
531
532         // Implementation assumes 'transferable' is never null.
533
if (transferable == null) {
534             if (emptyTransferable == null) {
535                 emptyTransferable = new Transferable JavaDoc() {
536                         public DataFlavor JavaDoc[] getTransferDataFlavors() {
537                             return new DataFlavor JavaDoc[0];
538                         }
539                         public boolean isDataFlavorSupported(DataFlavor JavaDoc flavor)
540                         {
541                             return false;
542                         }
543                         public Object JavaDoc getTransferData(DataFlavor JavaDoc flavor)
544                             throws UnsupportedFlavorException JavaDoc
545                         {
546                             throw new UnsupportedFlavorException JavaDoc(flavor);
547                         }
548                     };
549             }
550             transferable = emptyTransferable;
551         }
552     }
553
554     private static Transferable JavaDoc emptyTransferable;
555
556     /*
557      * fields
558      */

559
560     private transient DragSourceContextPeer peer;
561
562     /**
563      * The event which triggered the start of the drag.
564      *
565      * @serial
566      */

567     private DragGestureEvent JavaDoc trigger;
568
569     /**
570      * The current drag cursor.
571      *
572      * @serial
573      */

574     private Cursor JavaDoc cursor;
575
576     private transient Transferable JavaDoc transferable;
577
578     private transient DragSourceListener JavaDoc listener;
579
580     /**
581      * <code>true</code> if the custom drag cursor is used instead of the
582      * default one.
583      *
584      * @serial
585      */

586     private boolean useCustomCursor;
587
588     /**
589      * A bitwise mask of <code>DnDConstants</code> that represents the set of
590      * drop actions supported by the drag source for the drag operation associated
591      * with this <code>DragSourceContext.</code>
592      *
593      * @serial
594      */

595     private final int sourceActions;
596 }
597
Popular Tags