KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > TransferHandler


1 /*
2  * @(#)TransferHandler.java 1.30 05/08/26
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package javax.swing;
8
9 import java.awt.*;
10 import java.awt.event.*;
11 import java.awt.datatransfer.*;
12 import java.awt.dnd.*;
13 import java.beans.*;
14 import java.lang.reflect.*;
15 import java.io.*;
16 import java.util.TooManyListenersException JavaDoc;
17 import javax.swing.plaf.UIResource JavaDoc;
18 import javax.swing.event.*;
19
20 import com.sun.java.swing.SwingUtilities2;
21 import sun.reflect.misc.MethodUtil;
22
23 /**
24  * This class is used to handle the transfer of a <code>Transferable</code>
25  * to and from Swing components. The <code>Transferable</code> is used to
26  * represent data that is exchanged via a cut, copy, or paste
27  * to/from a clipboard. It is also used in drag-and-drop operations
28  * to represent a drag from a component, and a drop to a component.
29  * Swing provides functionality that automatically supports cut, copy,
30  * and paste keyboard bindings that use the functionality provided by
31  * an implementation of this class. Swing also provides functionality
32  * that automatically supports drag and drop that uses the functionality
33  * provided by an implementation of this class. The Swing developer can
34  * concentrate on specifying the semantics of a transfer primarily by setting
35  * the <code>transferHandler</code> property on a Swing component.
36  * <p>
37  * This class is implemented to provide a default behavior of transferring
38  * a component property simply by specifying the name of the property in
39  * the constructor. For example, to transfer the foreground color from
40  * one component to another either via the clipboard or a drag and drop operation
41  * a <code>TransferHandler</code> can be constructed with the string "foreground". The
42  * built in support will use the color returned by <code>getForeground</code> as the source
43  * of the transfer, and <code>setForeground</code> for the target of a transfer.
44  * <p>
45  * Please see
46  * <a HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/dnd.html">
47  * How to Use Drag and Drop and Data Transfer</a>,
48  * a section in <em>The Java Tutorial</em>, for more information.
49  *
50  *
51  * @author Timothy Prinzing
52  * @version 1.30 08/26/05
53  * @since 1.4
54  */

55 public class TransferHandler implements Serializable {
56
57     /**
58      * An <code>int</code> representing no transfer action.
59      */

60     public static final int NONE = DnDConstants.ACTION_NONE;
61
62     /**
63      * An <code>int</code> representing a &quot;copy&quot; transfer action.
64      * This value is used when data is copied to a clipboard
65      * or copied elsewhere in a drag and drop operation.
66      */

67     public static final int COPY = DnDConstants.ACTION_COPY;
68
69     /**
70      * An <code>int</code> representing a &quot;move&quot; transfer action.
71      * This value is used when data is moved to a clipboard (i.e. a cut)
72      * or moved elsewhere in a drag and drop operation.
73      */

74     public static final int MOVE = DnDConstants.ACTION_MOVE;
75
76     /**
77      * An <code>int</code> representing a source action capability of either
78      * &quot;copy&quot; or &quot;move&quot;.
79      */

80     public static final int COPY_OR_MOVE = DnDConstants.ACTION_COPY_OR_MOVE;
81     
82     /**
83      * An <code>int</code> representing a &quot;link&quot; transfer action.
84      * This value is used to specify that data should be linked in a drag
85      * and drop operation.
86      */

87     private static final int LINK = DnDConstants.ACTION_LINK;
88
89
90     /**
91      * Returns an <code>Action</code> that behaves like a 'cut' operation.
92      * That is, this will invoke <code>exportToClipboard</code> with
93      * a <code>MOVE</code> argument on the <code>TransferHandler</code>
94      * associated with the <code>JComponent</code> that is the source of
95      * the <code>ActionEvent</code>.
96      *
97      * @return cut Action
98      */

99     public static Action JavaDoc getCutAction() {
100         return cutAction;
101     }
102
103     /**
104      * Returns an <code>Action</code> that behaves like a 'copy' operation.
105      * That is, this will invoke <code>exportToClipboard</code> with
106      * a <code>COPY</code> argument on the <code>TransferHandler</code>
107      * associated with the <code>JComponent</code> that is the source of
108      * the <code>ActionEvent</code>.
109      *
110      * @return cut Action
111      */

112     public static Action JavaDoc getCopyAction() {
113         return copyAction;
114     }
115
116     /**
117      * Returns an <code>Action</code> that behaves like a 'paste' operation.
118      * That is, this will invoke <code>importData</code> on the
119      * <code>TransferHandler</code>
120      * associated with the <code>JComponent</code> that is the source of
121      * the <code>ActionEvent</code>.
122      *
123      * @return cut Action
124      */

125     public static Action JavaDoc getPasteAction() {
126         return pasteAction;
127     }
128
129     
130     /**
131      * Constructs a transfer handler that can transfer a Java Bean property
132      * from one component to another via the clipboard or a drag and drop
133      * operation.
134      *
135      * @param property the name of the property to transfer; this can
136      * be <code>null</code> if there is no property associated with the transfer
137      * handler (a subclass that performs some other kind of transfer, for example)
138      */

139     public TransferHandler(String JavaDoc property) {
140     propertyName = property;
141     }
142
143     /**
144      * Convenience constructor for subclasses.
145      */

146     protected TransferHandler() {
147     this(null);
148     }
149
150     /**
151      * Causes the Swing drag support to be initiated. This is called by
152      * the various UI implementations in the <code>javax.swing.plaf.basic</code>
153      * package if the dragEnabled property is set on the component.
154      * This can be called by custom UI
155      * implementations to use the Swing drag support. This method can also be called
156      * by a Swing extension written as a subclass of <code>JComponent</code>
157      * to take advantage of the Swing drag support.
158      * <p>
159      * The transfer <em>will not necessarily</em> have been completed at the
160      * return of this call (i.e. the call does not block waiting for the drop).
161      * The transfer will take place through the Swing implementation of the
162      * <code>java.awt.dnd</code> mechanism, requiring no further effort
163      * from the developer. The <code>exportDone</code> method will be called
164      * when the transfer has completed.
165      *
166      * @param comp the component holding the data to be transferred; this
167      * argument is provided to enable sharing of <code>TransferHandler</code>s by
168      * multiple components
169      * @param e the event that triggered the transfer
170      * @param action the transfer action initially requested; this should
171      * be a value of either <code>COPY</code> or <code>MOVE</code>;
172      * the value may be changed during the course of the drag operation
173      */

174     public void exportAsDrag(JComponent JavaDoc comp, InputEvent e, int action) {
175         int srcActions = getSourceActions(comp);
176     int dragAction = srcActions & action;
177     if (! (e instanceof MouseEvent)) {
178         // only mouse events supported for drag operations
179
dragAction = NONE;
180     }
181     if (dragAction != NONE && !GraphicsEnvironment.isHeadless()) {
182         if (recognizer == null) {
183         recognizer = new SwingDragGestureRecognizer(new DragHandler());
184         }
185         recognizer.gestured(comp, (MouseEvent)e, srcActions, dragAction);
186     } else {
187             exportDone(comp, null, NONE);
188         }
189     }
190
191     /**
192      * Causes a transfer from the given component to the
193      * given clipboard. This method is called by the default cut and
194      * copy actions registered in a component's action map.
195      * <p>
196      * The transfer will take place using the <code>java.awt.datatransfer</code>
197      * mechanism, requiring no further effort from the developer. Any data
198      * transfer <em>will</em> be complete and the <code>exportDone</code>
199      * method will be called with the action that occurred, before this method
200      * returns. Should the clipboard be unavailable when attempting to place
201      * data on it, the <code>IllegalStateException</code> thrown by
202      * {@link Clipboard#setContents(Transferable, ClipboardOwner)} will
203      * be propogated through this method. However,
204      * <code>exportDone</code> will first be called with an action
205      * of <code>NONE</code> for consistency.
206      *
207      * @param comp the component holding the data to be transferred; this
208      * argument is provided to enable sharing of <code>TransferHandler</code>s by
209      * multiple components
210      * @param clip the clipboard to transfer the data into
211      * @param action the transfer action requested; this should
212      * be a value of either <code>COPY</code> or <code>MOVE</code>;
213      * the operation performed is the intersection of the transfer
214      * capabilities given by getSourceActions and the requested action;
215      * the intersection may result in an action of <code>NONE</code>
216      * if the requested action isn't supported
217      * @throws IllegalStateException if the clipboard is currently unavailable
218      * @see Clipboard#setContents(Transferable, ClipboardOwner)
219      */

220     public void exportToClipboard(JComponent JavaDoc comp, Clipboard clip, int action)
221                                                   throws IllegalStateException JavaDoc {
222
223     int clipboardAction = getSourceActions(comp) & action;
224     if (clipboardAction != NONE) {
225             Transferable t = createTransferable(comp);
226             if (t != null) {
227                 try {
228                     clip.setContents(t, null);
229                     exportDone(comp, t, clipboardAction);
230                     return;
231                 } catch (IllegalStateException JavaDoc ise) {
232                     exportDone(comp, t, NONE);
233                     throw ise;
234                 }
235             }
236         }
237
238         exportDone(comp, null, NONE);
239     }
240
241     /**
242      * Causes a transfer to a component from a clipboard or a
243      * DND drop operation. The <code>Transferable</code> represents
244      * the data to be imported into the component.
245      *
246      * @param comp the component to receive the transfer; this
247      * argument is provided to enable sharing of <code>TransferHandler</code>s
248      * by multiple components
249      * @param t the data to import
250      * @return true if the data was inserted into the component, false otherwise
251      */

252     public boolean importData(JComponent JavaDoc comp, Transferable t) {
253     PropertyDescriptor prop = getPropertyDescriptor(comp);
254     if (prop != null) {
255         Method writer = prop.getWriteMethod();
256         if (writer == null) {
257         // read-only property. ignore
258
return false;
259         }
260         Class JavaDoc[] params = writer.getParameterTypes();
261         if (params.length != 1) {
262         // zero or more than one argument, ignore
263
return false;
264         }
265         DataFlavor flavor = getPropertyDataFlavor(params[0], t.getTransferDataFlavors());
266         if (flavor != null) {
267         try {
268             Object JavaDoc value = t.getTransferData(flavor);
269             Object JavaDoc[] args = { value };
270             MethodUtil.invoke(writer, comp, args);
271             return true;
272         } catch (Exception JavaDoc ex) {
273             System.err.println("Invocation failed");
274             // invocation code
275
}
276         }
277     }
278     return false;
279     }
280
281     /**
282      * Indicates whether a component would accept an import of the given
283      * set of data flavors prior to actually attempting to import it.
284      *
285      * @param comp the component to receive the transfer; this
286      * argument is provided to enable sharing of <code>TransferHandlers</code>
287      * by multiple components
288      * @param transferFlavors the data formats available
289      * @return true if the data can be inserted into the component, false otherwise
290      */

291     public boolean canImport(JComponent JavaDoc comp, DataFlavor[] transferFlavors) {
292     PropertyDescriptor prop = getPropertyDescriptor(comp);
293     if (prop != null) {
294         Method writer = prop.getWriteMethod();
295         if (writer == null) {
296         // read-only property. ignore
297
return false;
298         }
299         Class JavaDoc[] params = writer.getParameterTypes();
300         if (params.length != 1) {
301         // zero or more than one argument, ignore
302
return false;
303         }
304         DataFlavor flavor = getPropertyDataFlavor(params[0], transferFlavors);
305         if (flavor != null) {
306         return true;
307         }
308     }
309     return false;
310     }
311
312     /**
313      * Returns the type of transfer actions supported by the source.
314      * Some models are not mutable, so a transfer operation of <code>COPY</code>
315      * only should be advertised in that case.
316      *
317      * @param c the component holding the data to be transferred; this
318      * argument is provided to enable sharing of <code>TransferHandler</code>s
319      * by multiple components.
320      * @return <code>COPY</code> if the transfer property can be found,
321      * otherwise returns <code>NONE</code>; a return value of
322      * of <code>NONE</code> disables any transfers out of the component
323      */

324     public int getSourceActions(JComponent JavaDoc c) {
325     PropertyDescriptor prop = getPropertyDescriptor(c);
326     if (prop != null) {
327         return COPY;
328     }
329     return NONE;
330     }
331
332     /**
333      * Returns an object that establishes the look of a transfer. This is
334      * useful for both providing feedback while performing a drag operation and for
335      * representing the transfer in a clipboard implementation that has a visual
336      * appearance. The implementation of the <code>Icon</code> interface should
337      * not alter the graphics clip or alpha level.
338      * The icon implementation need not be rectangular or paint all of the
339      * bounding rectangle and logic that calls the icons paint method should
340      * not assume the all bits are painted. <code>null</code> is a valid return value
341      * for this method and indicates there is no visual representation provided.
342      * In that case, the calling logic is free to represent the
343      * transferable however it wants.
344      * <p>
345      * The default Swing logic will not do an alpha blended drag animation if
346      * the return is <code>null</code>.
347      *
348      * @param t the data to be transferred; this value is expected to have been
349      * created by the <code>createTransferable</code> method
350      * @return <code>null</code>, indicating
351      * there is no default visual representation
352      */

353     public Icon JavaDoc getVisualRepresentation(Transferable t) {
354     return null;
355     }
356
357     /**
358      * Creates a <code>Transferable</code> to use as the source for
359      * a data transfer. Returns the representation of the data to
360      * be transferred, or <code>null</code> if the component's
361      * property is <code>null</code>
362      *
363      * @param c the component holding the data to be transferred; this
364      * argument is provided to enable sharing of <code>TransferHandler</code>s
365      * by multiple components
366      * @return the representation of the data to be transferred, or
367      * <code>null</code> if the property associated with <code>c</code>
368      * is <code>null</code>
369      *
370      */

371     protected Transferable createTransferable(JComponent JavaDoc c) {
372     PropertyDescriptor property = getPropertyDescriptor(c);
373     if (property != null) {
374         return new PropertyTransferable(property, c);
375     }
376     return null;
377     }
378
379     /**
380      * Invoked after data has been exported. This method should remove
381      * the data that was transferred if the action was <code>MOVE</code>.
382      * <p>
383      * This method is implemented to do nothing since <code>MOVE</code>
384      * is not a supported action of this implementation
385      * (<code>getSourceActions</code> does not include <code>MOVE</code>).
386      *
387      * @param source the component that was the source of the data
388      * @param data The data that was transferred or possibly null
389      * if the action is <code>NONE</code>.
390      * @param action the actual action that was performed
391      */

392     protected void exportDone(JComponent JavaDoc source, Transferable data, int action) {
393     }
394
395     /**
396      * Fetches the property descriptor for the property assigned to this transfer
397      * handler on the given component (transfer handler may be shared). This
398      * returns <code>null</code> if the property descriptor can't be found
399      * or there is an error attempting to fetch the property descriptor.
400      */

401     private PropertyDescriptor getPropertyDescriptor(JComponent JavaDoc comp) {
402     if (propertyName == null) {
403         return null;
404     }
405     Class JavaDoc k = comp.getClass();
406     BeanInfo bi;
407     try {
408         bi = Introspector.getBeanInfo(k);
409     } catch (IntrospectionException ex) {
410         return null;
411     }
412     PropertyDescriptor props[] = bi.getPropertyDescriptors();
413     for (int i=0; i < props.length; i++) {
414         if (propertyName.equals(props[i].getName())) {
415                 Method reader = props[i].getReadMethod();
416
417                 if (reader != null) {
418                     Class JavaDoc[] params = reader.getParameterTypes();
419
420                     if (params == null || params.length == 0) {
421                         // found the desired descriptor
422
return props[i];
423                     }
424                 }
425         }
426     }
427     return null;
428     }
429
430     /**
431      * Fetches the data flavor from the array of possible flavors that
432      * has data of the type represented by property type. Null is
433      * returned if there is no match.
434      */

435     private DataFlavor getPropertyDataFlavor(Class JavaDoc k, DataFlavor[] flavors) {
436     for(int i = 0; i < flavors.length; i++) {
437         DataFlavor flavor = flavors[i];
438         if ("application".equals(flavor.getPrimaryType()) &&
439         "x-java-jvm-local-objectref".equals(flavor.getSubType()) &&
440         k.isAssignableFrom(flavor.getRepresentationClass())) {
441
442         return flavor;
443         }
444     }
445     return null;
446     }
447
448
449     private String JavaDoc propertyName;
450     private static SwingDragGestureRecognizer recognizer = null;
451     private static DropTargetListener dropLinkage = null;
452
453     private static DropTargetListener getDropTargetListener() {
454     if (dropLinkage == null) {
455         dropLinkage = new DropHandler();
456     }
457     return dropLinkage;
458     }
459
460     static class PropertyTransferable implements Transferable {
461
462     PropertyTransferable(PropertyDescriptor p, JComponent JavaDoc c) {
463         property = p;
464         component = c;
465     }
466
467     // --- Transferable methods ----------------------------------------------
468

469     /**
470      * Returns an array of <code>DataFlavor</code> objects indicating the flavors the data
471      * can be provided in. The array should be ordered according to preference
472      * for providing the data (from most richly descriptive to least descriptive).
473      * @return an array of data flavors in which this data can be transferred
474      */

475         public DataFlavor[] getTransferDataFlavors() {
476         DataFlavor[] flavors = new DataFlavor[1];
477         Class JavaDoc propertyType = property.getPropertyType();
478         String JavaDoc mimeType = DataFlavor.javaJVMLocalObjectMimeType + ";class=" + propertyType.getName();
479         try {
480         flavors[0] = new DataFlavor(mimeType);
481         } catch (ClassNotFoundException JavaDoc cnfe) {
482         flavors = new DataFlavor[0];
483         }
484         return flavors;
485     }
486
487     /**
488      * Returns whether the specified data flavor is supported for
489      * this object.
490      * @param flavor the requested flavor for the data
491      * @return true if this <code>DataFlavor</code> is supported,
492          * otherwise false
493      */

494         public boolean isDataFlavorSupported(DataFlavor flavor) {
495         Class JavaDoc propertyType = property.getPropertyType();
496         if ("application".equals(flavor.getPrimaryType()) &&
497         "x-java-jvm-local-objectref".equals(flavor.getSubType()) &&
498         flavor.getRepresentationClass().isAssignableFrom(propertyType)) {
499
500         return true;
501         }
502         return false;
503     }
504
505     /**
506      * Returns an object which represents the data to be transferred. The class
507      * of the object returned is defined by the representation class of the flavor.
508      *
509      * @param flavor the requested flavor for the data
510      * @see DataFlavor#getRepresentationClass
511      * @exception IOException if the data is no longer available
512      * in the requested flavor.
513      * @exception UnsupportedFlavorException if the requested data flavor is
514      * not supported.
515      */

516         public Object JavaDoc getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
517         if (! isDataFlavorSupported(flavor)) {
518         throw new UnsupportedFlavorException(flavor);
519         }
520         Method reader = property.getReadMethod();
521         Object JavaDoc value = null;
522         try {
523         value = MethodUtil.invoke(reader, component, null);
524         } catch (Exception JavaDoc ex) {
525         throw new IOException("Property read failed: " + property.getName());
526         }
527         return value;
528     }
529
530     JComponent JavaDoc component;
531     PropertyDescriptor property;
532     }
533
534     /**
535      * This is the default drop target for drag and drop operations if
536      * one isn't provided by the developer. <code>DropTarget</code>
537      * only supports one <code>DropTargetListener</code> and doesn't
538      * function properly if it isn't set.
539      * This class sets the one listener as the linkage of drop handling
540      * to the <code>TransferHandler</code>, and adds support for
541      * additional listeners which some of the <code>ComponentUI</code>
542      * implementations install to manipulate a drop insertion location.
543      */

544     static class SwingDropTarget extends DropTarget implements UIResource JavaDoc {
545
546     SwingDropTarget(JComponent JavaDoc c) {
547             super();
548             setComponent(c);
549             try {
550                 super.addDropTargetListener(getDropTargetListener());
551             } catch (TooManyListenersException JavaDoc tmle) {}
552     }
553
554         public void addDropTargetListener(DropTargetListener dtl) throws TooManyListenersException JavaDoc {
555             // Since the super class only supports one DropTargetListener,
556
// and we add one from the constructor, we always add to the
557
// extended list.
558
if (listenerList == null) {
559                 listenerList = new EventListenerList();
560             }
561             listenerList.add(DropTargetListener.class, dtl);
562     }
563
564         public void removeDropTargetListener(DropTargetListener dtl) {
565             if (listenerList != null) {
566                 listenerList.remove(DropTargetListener.class, dtl);
567             }
568     }
569
570     // --- DropTargetListener methods (multicast) --------------------------
571

572         public void dragEnter(DropTargetDragEvent e) {
573         super.dragEnter(e);
574         if (listenerList != null) {
575         Object JavaDoc[] listeners = listenerList.getListenerList();
576         for (int i = listeners.length-2; i>=0; i-=2) {
577             if (listeners[i]==DropTargetListener.class) {
578             ((DropTargetListener)listeners[i+1]).dragEnter(e);
579             }
580         }
581         }
582     }
583
584         public void dragOver(DropTargetDragEvent e) {
585         super.dragOver(e);
586         if (listenerList != null) {
587         Object JavaDoc[] listeners = listenerList.getListenerList();
588         for (int i = listeners.length-2; i>=0; i-=2) {
589             if (listeners[i]==DropTargetListener.class) {
590             ((DropTargetListener)listeners[i+1]).dragOver(e);
591             }
592         }
593         }
594     }
595
596         public void dragExit(DropTargetEvent e) {
597         super.dragExit(e);
598         if (listenerList != null) {
599         Object JavaDoc[] listeners = listenerList.getListenerList();
600         for (int i = listeners.length-2; i>=0; i-=2) {
601             if (listeners[i]==DropTargetListener.class) {
602             ((DropTargetListener)listeners[i+1]).dragExit(e);
603             }
604         }
605         }
606     }
607
608         public void drop(DropTargetDropEvent e) {
609         super.drop(e);
610         if (listenerList != null) {
611         Object JavaDoc[] listeners = listenerList.getListenerList();
612         for (int i = listeners.length-2; i>=0; i-=2) {
613             if (listeners[i]==DropTargetListener.class) {
614             ((DropTargetListener)listeners[i+1]).drop(e);
615             }
616         }
617         }
618     }
619
620         public void dropActionChanged(DropTargetDragEvent e) {
621         super.dropActionChanged(e);
622         if (listenerList != null) {
623         Object JavaDoc[] listeners = listenerList.getListenerList();
624         for (int i = listeners.length-2; i>=0; i-=2) {
625             if (listeners[i]==DropTargetListener.class) {
626             ((DropTargetListener)listeners[i+1]).dropActionChanged(e);
627             }
628         }
629         }
630     }
631
632         private EventListenerList listenerList;
633     }
634
635     private static class DropHandler implements DropTargetListener, Serializable {
636         
637         private boolean canImport;
638         
639         private boolean actionSupported(int action) {
640             return (action & (COPY_OR_MOVE | LINK)) != NONE;
641         }
642
643     // --- DropTargetListener methods -----------------------------------
644

645         public void dragEnter(DropTargetDragEvent e) {
646         DataFlavor[] flavors = e.getCurrentDataFlavors();
647
648         JComponent JavaDoc c = (JComponent JavaDoc)e.getDropTargetContext().getComponent();
649         TransferHandler JavaDoc importer = c.getTransferHandler();
650             
651             if (importer != null && importer.canImport(c, flavors)) {
652                 canImport = true;
653             } else {
654                 canImport = false;
655             }
656             
657             int dropAction = e.getDropAction();
658             
659             if (canImport && actionSupported(dropAction)) {
660         e.acceptDrag(dropAction);
661         } else {
662         e.rejectDrag();
663         }
664     }
665
666         public void dragOver(DropTargetDragEvent e) {
667             int dropAction = e.getDropAction();
668             
669             if (canImport && actionSupported(dropAction)) {
670                 e.acceptDrag(dropAction);
671             } else {
672                 e.rejectDrag();
673             }
674     }
675
676         public void dragExit(DropTargetEvent e) {
677     }
678
679         public void drop(DropTargetDropEvent e) {
680             int dropAction = e.getDropAction();
681
682             JComponent JavaDoc c = (JComponent JavaDoc)e.getDropTargetContext().getComponent();
683             TransferHandler JavaDoc importer = c.getTransferHandler();
684
685         if (canImport && importer != null && actionSupported(dropAction)) {
686         e.acceptDrop(dropAction);
687                 
688                 try {
689                     Transferable t = e.getTransferable();
690             e.dropComplete(importer.importData(c, t));
691                 } catch (RuntimeException JavaDoc re) {
692                     e.dropComplete(false);
693                 }
694         } else {
695         e.rejectDrop();
696         }
697     }
698
699         public void dropActionChanged(DropTargetDragEvent e) {
700             int dropAction = e.getDropAction();
701             
702             if (canImport && actionSupported(dropAction)) {
703                 e.acceptDrag(dropAction);
704             } else {
705                 e.rejectDrag();
706             }
707     }
708     }
709
710     /**
711      * This is the default drag handler for drag and drop operations that
712      * use the <code>TransferHandler</code>.
713      */

714     private static class DragHandler implements DragGestureListener, DragSourceListener {
715         
716         private boolean scrolls;
717
718     // --- DragGestureListener methods -----------------------------------
719

720     /**
721      * a Drag gesture has been recognized
722      */

723         public void dragGestureRecognized(DragGestureEvent dge) {
724         JComponent JavaDoc c = (JComponent JavaDoc) dge.getComponent();
725         TransferHandler JavaDoc th = c.getTransferHandler();
726         Transferable t = th.createTransferable(c);
727         if (t != null) {
728                 scrolls = c.getAutoscrolls();
729                 c.setAutoscrolls(false);
730                 try {
731                     dge.startDrag(null, t, this);
732                     return;
733                 } catch (RuntimeException JavaDoc re) {
734                     c.setAutoscrolls(scrolls);
735                 }
736         }
737             
738             th.exportDone(c, t, NONE);
739     }
740
741     // --- DragSourceListener methods -----------------------------------
742

743     /**
744      * as the hotspot enters a platform dependent drop site
745      */

746         public void dragEnter(DragSourceDragEvent dsde) {
747     }
748   
749     /**
750      * as the hotspot moves over a platform dependent drop site
751      */

752         public void dragOver(DragSourceDragEvent dsde) {
753     }
754   
755     /**
756      * as the hotspot exits a platform dependent drop site
757      */

758         public void dragExit(DragSourceEvent dsde) {
759     }
760   
761     /**
762      * as the operation completes
763      */

764         public void dragDropEnd(DragSourceDropEvent dsde) {
765             DragSourceContext dsc = dsde.getDragSourceContext();
766             JComponent JavaDoc c = (JComponent JavaDoc)dsc.getComponent();
767         if (dsde.getDropSuccess()) {
768                 c.getTransferHandler().exportDone(c, dsc.getTransferable(), dsde.getDropAction());
769         } else {
770                 c.getTransferHandler().exportDone(c, dsc.getTransferable(), NONE);
771             }
772             c.setAutoscrolls(scrolls);
773     }
774   
775         public void dropActionChanged(DragSourceDragEvent dsde) {
776     }
777     }
778
779     private static class SwingDragGestureRecognizer extends DragGestureRecognizer {
780
781     SwingDragGestureRecognizer(DragGestureListener dgl) {
782         super(DragSource.getDefaultDragSource(), null, NONE, dgl);
783     }
784
785     void gestured(JComponent JavaDoc c, MouseEvent e, int srcActions, int action) {
786         setComponent(c);
787             setSourceActions(srcActions);
788         appendEvent(e);
789         fireDragGestureRecognized(action, e.getPoint());
790     }
791
792     /**
793      * register this DragGestureRecognizer's Listeners with the Component
794      */

795         protected void registerListeners() {
796     }
797
798     /**
799      * unregister this DragGestureRecognizer's Listeners with the Component
800      *
801      * subclasses must override this method
802      */

803         protected void unregisterListeners() {
804     }
805
806     }
807
808     static final Action JavaDoc cutAction = new TransferAction("cut");
809     static final Action JavaDoc copyAction = new TransferAction("copy");
810     static final Action JavaDoc pasteAction = new TransferAction("paste");
811     
812     static class TransferAction extends AbstractAction JavaDoc implements UIResource JavaDoc {
813
814     TransferAction(String JavaDoc name) {
815         super(name);
816     }
817
818         public void actionPerformed(ActionEvent e) {
819         Object JavaDoc src = e.getSource();
820         if (src instanceof JComponent JavaDoc) {
821         JComponent JavaDoc c = (JComponent JavaDoc) src;
822         TransferHandler JavaDoc th = c.getTransferHandler();
823         Clipboard clipboard = getClipboard(c);
824         String JavaDoc name = (String JavaDoc) getValue(Action.NAME);
825
826                 Transferable trans = null;
827
828                 // any of these calls may throw IllegalStateException
829
try {
830                     if ((clipboard != null) && (th != null) && (name != null)) {
831                         if ("cut".equals(name)) {
832                             th.exportToClipboard(c, clipboard, MOVE);
833                         } else if ("copy".equals(name)) {
834                             th.exportToClipboard(c, clipboard, COPY);
835                         } else if ("paste".equals(name)) {
836                             trans = clipboard.getContents(null);
837                         }
838                     }
839                 } catch (IllegalStateException JavaDoc ise) {
840                     // clipboard was unavailable
841
UIManager.getLookAndFeel().provideErrorFeedback(c);
842                     return;
843                 }
844
845                 // this is a paste action, import data into the component
846
if (trans != null) {
847                     th.importData(c, trans);
848                 }
849         }
850     }
851
852     /**
853      * Returns the clipboard to use for cut/copy/paste.
854      */

855         private Clipboard getClipboard(JComponent JavaDoc c) {
856         if (SwingUtilities2.canAccessSystemClipboard()) {
857         return c.getToolkit().getSystemClipboard();
858         }
859         Clipboard clipboard = (Clipboard)sun.awt.AppContext.getAppContext().
860         get(SandboxClipboardKey);
861         if (clipboard == null) {
862         clipboard = new Clipboard("Sandboxed Component Clipboard");
863         sun.awt.AppContext.getAppContext().put(SandboxClipboardKey,
864                                clipboard);
865         }
866         return clipboard;
867     }
868
869     /**
870      * Key used in app context to lookup Clipboard to use if access to
871      * System clipboard is denied.
872      */

873         private static Object JavaDoc SandboxClipboardKey = new Object JavaDoc();
874
875     }
876
877 }
878
879
880
881
Popular Tags