KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > suberic > pooka > gui > dnd > MultipleTransferHandler


1 //The contents of this file are subject to the Mozilla Public License Version 1.1
2
//(the "License"); you may not use this file except in compliance with the
3
//License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
4
//
5
//Software distributed under the License is distributed on an "AS IS" basis,
6
//WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
7
//for the specific language governing rights and
8
//limitations under the License.
9
//
10
//The Original Code is "The Columba Project"
11
//
12
//The Initial Developers of the Original Code are Frederik Dietz and Timo Stich.
13
//Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
14
//
15
//All Rights Reserved.
16
package net.suberic.pooka.gui.dnd;
17
18 import java.awt.datatransfer.Clipboard JavaDoc;
19 import java.awt.datatransfer.DataFlavor JavaDoc;
20 import java.awt.datatransfer.Transferable JavaDoc;
21 import java.awt.event.InputEvent JavaDoc;
22 import java.lang.reflect.InvocationTargetException JavaDoc;
23 import java.lang.reflect.Method JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.List JavaDoc;
27
28 import javax.swing.Icon JavaDoc;
29 import javax.swing.JComponent JavaDoc;
30 import javax.swing.TransferHandler JavaDoc;
31
32
33 /**
34  * A transfer handler that is composed from many transfer handlers.
35  * When setting a TransferHandler on a component, the new transfer handler
36  * is the only one used in a Drag and Drop action. Most of the times, this is
37  * fine but sometimes you want to preserve the behaviour of the component's
38  * default transfer handler. You only want to implement one specific data flavor
39  * to the component, not redoing those feature already implemented.
40  * This class lets a component to have several
41  * transfer handlers instead of one.
42  * <p>
43  * For example, the JTextArea has a transfer handler that supports draging and dropping
44  * strings into it by default. Say that you want to add support of DnD of a file into the
45  * text. Instead of mimicing behaviour of DnD of strings, you will only implement a
46  * transfer handler that supports the file list data flavor. Add these two transfer handler
47  * to this class and set this as the component transferhandler and everything is solved.
48  * <p>
49  * This chain of resposibility object is only good for adding new data flavors when importing, it will
50  * not give extra features when dragging from the component to another component. When starting
51  * a drag, the first transfer handler is used as the source handler. This is important to have
52  * the transfer handler with the most export support implemented, otherwise the component will
53  * lose its DnD export features. The default handler is always the first in the list, but can also
54  * be set by the corresponding method.
55  * <p>
56  * The behind the scenes implementation tries to cohere with the design pattern "Chain of responsibility".
57  * The actual implementation is internally a list that is ordered, ie TransferHandlers that
58  * are added first, is check first. If there are two transfer handlers that supports the same
59  * type of data flavors, the first one in the list is the one used.
60  * <p>
61  * Note that this transfer handler will put an overhead for each transferhandler.
62  * @author redsolo
63  */

64 public class MultipleTransferHandler extends TransferHandler JavaDoc {
65
66   private List JavaDoc transferHandlers = new ArrayList JavaDoc();
67   
68   private TransferHandler JavaDoc dragSourceHandler;
69
70   /**
71    * Adds the transfer handler to this handler.
72    * @param handler the new handler.
73    */

74   public void addTransferHandler(TransferHandler JavaDoc handler) {
75     if (!transferHandlers.contains(handler)) {
76       transferHandlers.add(handler);
77     }
78     if (dragSourceHandler == null) {
79       dragSourceHandler = handler;
80     }
81   }
82
83   /**
84    * Removes the transfer handler from this handler.
85    * @param handler the handler.
86    */

87   public void removeTransferHandler(TransferHandler JavaDoc handler) {
88     transferHandlers.remove(handler);
89     if (handler == dragSourceHandler) {
90       if (transferHandlers.size() > 0) {
91     dragSourceHandler = (TransferHandler JavaDoc) transferHandlers.get(0);
92       } else {
93     dragSourceHandler = null;
94       }
95     }
96   }
97
98   /**
99    * Returns a list with all transfer handlers.
100    * @return a list with all transfer handlers.
101    */

102   public List JavaDoc getTransferHandlers() {
103     return (List JavaDoc) ((ArrayList JavaDoc) transferHandlers).clone();
104   }
105   
106   /**
107    * Sets the transfer handler to use as the drag source.
108    * The default implementation is to use the first transfer handler in the list.
109    * @param newDragHandler the new drag source transfer handler.
110    */

111   public void setDragSourceTransferHandler(TransferHandler JavaDoc newDragHandler) {
112     dragSourceHandler = newDragHandler;
113   }
114   
115   /**
116    * Returns the transfer handler when dragging from the component.
117    * @return the transfer handler when dragging from the component.
118    */

119   public TransferHandler JavaDoc getDragSourceTransferHandler() {
120     if (dragSourceHandler == null) {
121       if (transferHandlers.size() == 0) {
122     throw new IllegalStateException JavaDoc("The multiple transfer handler must have at least one TransferHandler.");
123       }
124       dragSourceHandler = (TransferHandler JavaDoc) transferHandlers.get(0);
125     }
126     return dragSourceHandler;
127   }
128
129   // ---------- Methods that handles importing of objects. ----------
130

131   /** {@inheritDoc} */
132   public boolean canImport(JComponent JavaDoc comp, DataFlavor JavaDoc[] transferFlavors) {
133     boolean canImport = false;
134     for (Iterator JavaDoc iterator = transferHandlers.iterator(); (iterator.hasNext()) && (!canImport);) {
135       TransferHandler JavaDoc handler = (TransferHandler JavaDoc) iterator.next();
136       canImport = handler.canImport(comp, transferFlavors);
137     }
138     return canImport;
139   }
140   
141   /** {@inheritDoc} */
142   public boolean importData(JComponent JavaDoc comp, Transferable JavaDoc t) {
143     boolean wasImported = false;
144     
145     for (Iterator JavaDoc iterator = transferHandlers.iterator(); (iterator.hasNext()) && (!wasImported);) {
146       TransferHandler JavaDoc handler = (TransferHandler JavaDoc) iterator.next();
147       if (handler.canImport(comp, t.getTransferDataFlavors())) {
148     wasImported = handler.importData(comp, t);
149       }
150     }
151     return wasImported;
152   }
153   
154   // ---------- Methods that handles exporting of objects. ----------
155

156   /** {@inheritDoc} */
157   public int getSourceActions(JComponent JavaDoc c) {
158     return getDragSourceTransferHandler().getSourceActions(c);
159   }
160   
161   /** {@inheritDoc} */
162   public void exportAsDrag(JComponent JavaDoc comp, InputEvent JavaDoc e, int action) {
163     getDragSourceTransferHandler().exportAsDrag(comp, e, action);
164   }
165   
166   /** {@inheritDoc} */
167   public void exportToClipboard(JComponent JavaDoc comp, Clipboard JavaDoc clip, int action) {
168     getDragSourceTransferHandler().exportToClipboard(comp, clip, action);
169   }
170   
171   /** {@inheritDoc} */
172   public Icon JavaDoc getVisualRepresentation(Transferable JavaDoc t) {
173     return getDragSourceTransferHandler().getVisualRepresentation(t);
174   }
175
176   /** {@inheritDoc} */
177   protected Transferable JavaDoc createTransferable(JComponent JavaDoc c) {
178     return (Transferable JavaDoc) ignoreProtectedAccess("createTransferable",
179                         new Class JavaDoc[] {JComponent JavaDoc.class},
180                         new Object JavaDoc[]{c});
181   }
182   
183   /** {@inheritDoc} */
184   protected void exportDone(JComponent JavaDoc source, Transferable JavaDoc data, int action) {
185     ignoreProtectedAccess("exportDone",
186               new Class JavaDoc[] {JComponent JavaDoc.class, Transferable JavaDoc.class, int.class},
187               new Object JavaDoc[]{source, data, new Integer JavaDoc(action)});
188   }
189   
190   /**
191    * Calls the method and ignores the protected access modifier on the TransferHandler class.
192    * This is necessary due to the fact the needed methods have protected access in the TransferHandler
193    * class. The Swing framework bypass this "feature" by having the cooperating classes in the same package.
194    * And since package access gives access before the protected modifier, then they dont have any
195    * problem doing this. But for other developers, there is no other way than to cheat using
196    * the reflection API.
197    * <p>
198    * The method calls the specified methodname on the default drag source TransferHandler, bypassing
199    * the protected access modifier.
200    * @param methodName the name of the method to call.
201    * @param methodArguments the type of arguments that the method has.
202    * @param arguments the arguments to send when calling the method.
203    * @return an Object if the method returns one. If the method doesnt return an object, null is returned.
204    */

205   private Object JavaDoc ignoreProtectedAccess(String JavaDoc methodName, Class JavaDoc[] methodArguments, Object JavaDoc[] arguments) {
206     Object JavaDoc object = null;
207     try {
208       Method JavaDoc method = TransferHandler JavaDoc.class.getDeclaredMethod(methodName, methodArguments);
209       method.setAccessible(true);
210       object = (Transferable JavaDoc) method.invoke(getDragSourceTransferHandler(), arguments);
211     } catch (SecurityException JavaDoc se) {
212     } catch (NoSuchMethodException JavaDoc nsme) {
213     } catch (IllegalArgumentException JavaDoc iae) {
214     } catch (IllegalAccessException JavaDoc iace) {
215     } catch (InvocationTargetException JavaDoc ite) {
216     }
217     return object;
218   }
219 }
220
Popular Tags