KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > explorer > view > DragDropUtilities


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.openide.explorer.view;
21
22 import java.awt.Toolkit JavaDoc;
23 import java.awt.datatransfer.Clipboard JavaDoc;
24 import java.awt.datatransfer.Transferable JavaDoc;
25 import java.awt.datatransfer.UnsupportedFlavorException JavaDoc;
26 import java.awt.dnd.DnDConstants JavaDoc;
27 import java.awt.event.ActionEvent JavaDoc;
28 import java.awt.event.ActionListener JavaDoc;
29 import java.io.IOException JavaDoc;
30 import java.util.ArrayList JavaDoc;
31 import java.util.Arrays JavaDoc;
32 import java.util.Iterator JavaDoc;
33 import java.util.List JavaDoc;
34 import java.util.TreeSet JavaDoc;
35 import javax.swing.JMenuItem JavaDoc;
36 import javax.swing.JPopupMenu JavaDoc;
37 import javax.swing.SwingUtilities JavaDoc;
38 import javax.swing.tree.TreeNode JavaDoc;
39 import org.netbeans.modules.openide.explorer.ExternalDragAndDrop;
40 import org.openide.DialogDisplayer;
41 import org.openide.NotifyDescriptor;
42 import org.openide.NotifyDescriptor.Message;
43 import org.openide.awt.Mnemonics;
44 import org.openide.nodes.Node;
45 import org.openide.util.Exceptions;
46 import org.openide.util.Lookup;
47 import org.openide.util.NbBundle;
48 import org.openide.util.UserCancelException;
49 import org.openide.util.datatransfer.ExClipboard;
50 import org.openide.util.datatransfer.ExTransferable;
51 import org.openide.util.datatransfer.ExTransferable.Multi;
52 import org.openide.util.datatransfer.MultiTransferObject;
53 import org.openide.util.datatransfer.PasteType;
54
55 /** Class that provides methods for common tasks needed during
56 * drag and drop when working with explorer views.
57 *
58 * @author Dafe Simonek
59 */

60 final class DragDropUtilities extends Object JavaDoc {
61     static final boolean dragAndDropEnabled = Boolean.parseBoolean(System.getProperty("netbeans.dnd.enabled", "true")); // NOI18N
62
static final int NODE_UP = -1;
63     static final int NODE_CENTRAL = 0;
64     static final int NODE_DOWN = 1;
65     static Runnable JavaDoc postDropRun = null;
66
67     // helper constants
68
static final int NoDrag = 0;
69     static final int NoDrop = 1;
70
71     /** No need to instantiate this class */
72     private DragDropUtilities() {
73     }
74
75     /** Utility method.
76     * @return true if given node supports given action,
77     * false otherwise.
78     */

79     static boolean checkNodeForAction(Node JavaDoc node, int dragAction) {
80         if (
81             node.canCut() &&
82                 ((dragAction == DnDConstants.ACTION_MOVE) || (dragAction == DnDConstants.ACTION_COPY_OR_MOVE))
83         ) {
84             return true;
85         }
86
87         if (
88             node.canCopy() &&
89                 ((dragAction == DnDConstants.ACTION_COPY) || (dragAction == DnDConstants.ACTION_COPY_OR_MOVE) ||
90                 (dragAction == DnDConstants.ACTION_LINK) || (dragAction == DnDConstants.ACTION_REFERENCE))
91         ) {
92             return true;
93         }
94
95         // hmmm, conditions not satisfied..
96
return false;
97     }
98
99     /** Gets right transferable of given nodes (according to given
100     * drag action) and also converts the transferable.<br>
101     * Can be called only with correct action constant.
102     * @return The transferable.
103     */

104     static Transferable JavaDoc getNodeTransferable(Node JavaDoc[] nodes, int dragAction)
105     throws IOException JavaDoc {
106         Transferable JavaDoc[] tArray = new Transferable JavaDoc[nodes.length];
107
108         for (int i = 0; i < nodes.length; i++) {
109             if ((dragAction & DnDConstants.ACTION_MOVE) != 0) {
110                 tArray[i] = nodes[i].clipboardCut();
111             } else {
112                 tArray[i] = nodes[i].drag ();
113             }
114         }
115         Transferable JavaDoc result;
116         if (tArray.length == 1) {
117             // only one node, so return regular single transferable
118
result = tArray[0];
119         } else {
120             // enclose the transferables into multi transferable
121
result = ExternalDragAndDrop.maybeAddExternalFileDnd( new Multi(tArray) );
122         }
123
124         Clipboard JavaDoc c = getClipboard();
125         if (c instanceof ExClipboard) {
126             return ((ExClipboard) c).convert(result);
127         } else {
128             return result;
129         }
130     }
131
132     /** Returns transferable of given node
133     * @return The transferable.
134     */

135     static Transferable JavaDoc getNodeTransferable(Node JavaDoc node, int dragAction)
136     throws IOException JavaDoc {
137         return getNodeTransferable(new Node JavaDoc[] { node }, dragAction);
138     }
139
140     /** Sets a runnable it will be executed after drop action is performed.
141      * @param run a runnable for execution */

142     static void setPostDropRun(Runnable JavaDoc run) {
143         postDropRun = run;
144     }
145
146     /* Invokes the stored runnable if it is there and than set to null.
147      */

148     static private void invokePostDropRun() {
149         if (postDropRun != null) {
150             SwingUtilities.invokeLater(postDropRun);
151             postDropRun = null;
152         }
153     }
154
155     /**
156      * Performs the drop. Performs paste on given paste type.
157      * (part of bugfix #37279, performPaste returns array of new nodes in target folder)
158      * @param type paste type
159      * @param targetFolder target folder for given paste type, can be null
160      * @return array of new added nodes in target folder
161      */

162     static Node JavaDoc[] performPaste(PasteType type, Node JavaDoc targetFolder) {
163         //System.out.println("performing drop...."+type); // NOI18N
164
try {
165             if (targetFolder == null) {
166                 // call paste action
167
type.paste();
168
169                 return new Node JavaDoc[] { };
170             }
171
172             Node JavaDoc[] preNodes = targetFolder.getChildren().getNodes(true);
173
174             // call paste action
175
type.paste();
176
177             Node JavaDoc[] postNodes = targetFolder.getChildren().getNodes(true);
178
179             // calculate new nodes
180
List JavaDoc<Node JavaDoc> pre = Arrays.asList(preNodes);
181             List JavaDoc<Node JavaDoc> post = Arrays.asList(postNodes);
182             Iterator JavaDoc<Node JavaDoc> it = post.iterator();
183             List JavaDoc<Node JavaDoc> diff = new ArrayList JavaDoc<Node JavaDoc>();
184
185             while (it.hasNext()) {
186                 Node JavaDoc n = it.next();
187
188                 if (!pre.contains(n)) {
189                     diff.add(n);
190                 }
191             }
192
193             return diff.toArray(new Node JavaDoc[diff.size()]);
194
195             /*Clipboard clipboard = T opManager.getDefault().getClipboard();
196             if (trans != null) {
197               ClipboardOwner owner = trans instanceof ClipboardOwner ?
198                 (ClipboardOwner)trans
199               :
200                 new StringSelection ("");
201               clipboard.setContents(trans, owner);
202             }*/

203         } catch (UserCancelException exc) {
204             // ignore - user just pressed cancel in some dialog....
205
return new Node JavaDoc[] { };
206         } catch (IOException JavaDoc e) {
207             Exceptions.printStackTrace(e);
208
209             return new Node JavaDoc[] { };
210         }
211     }
212
213     /** Returns array of paste types for given transferable.
214     * If given transferable contains multiple transferables,
215     * multi paste type which encloses paste types of all contained
216     * transferables is returned.
217     * Returns empty array if given node did not accepted the transferable
218     * (or some sub-transferables in multi transferable)
219     *
220     * @param node given node to ask fro paste types
221     * @param trans transferable to discover
222     */

223     static PasteType[] getPasteTypes(Node JavaDoc node, Transferable JavaDoc trans) {
224         if (!trans.isDataFlavorSupported(ExTransferable.multiFlavor)) {
225             // only single, so return paste types
226
PasteType[] pt = null;
227
228             try {
229                 pt = node.getPasteTypes(trans);
230             } catch (NullPointerException JavaDoc npe) {
231                 Exceptions.printStackTrace(npe);
232
233                 // there are not paste types
234
}
235
236             return pt;
237         } else {
238             // multi transferable, we must do extra work
239
try {
240                 MultiTransferObject obj = (MultiTransferObject) trans.getTransferData(ExTransferable.multiFlavor);
241                 int count = obj.getCount();
242                 Transferable JavaDoc[] t = new Transferable JavaDoc[count];
243                 PasteType[] p = new PasteType[count];
244                 PasteType[] curTypes = null;
245
246                 // extract default paste types of transferables
247
for (int i = 0; i < count; i++) {
248                     t[i] = obj.getTransferableAt(i);
249                     curTypes = node.getPasteTypes(t[i]);
250
251                     // return if not accepted
252
if (curTypes.length == 0) {
253                         return curTypes;
254                     }
255
256                     p[i] = curTypes[0];
257                 }
258
259                 // return new multi paste type
260
return new PasteType[] { new MultiPasteType(t, p) };
261             } catch (UnsupportedFlavorException JavaDoc e) {
262                 // ignore and return empty array
263
} catch (IOException JavaDoc e) {
264                 // ignore and return empty array
265
}
266         }
267
268         return new PasteType[0];
269     }
270
271     /** Returns drop type for given transferable and drop action
272     * If given transferable contains multiple transferables,
273     * multi paste type which encloses drop types of all contained
274     * transferables is returned.
275     * Returns null if given node did not accepted the transferable
276     * (or some sub-transferables in multi transferable)
277     *
278     * @param node given node to ask fro paste types
279     * @param trans transferable to discover
280     * @param action drop action
281     * @param dropIndex where the object is dropped
282     */

283     static PasteType getDropType(Node JavaDoc node, Transferable JavaDoc trans, int action, int dropIndex) {
284         PasteType paste = null;
285         
286         try {
287             paste = node.getDropType(trans, action, dropIndex);
288             if (paste!=null)
289                 return paste;
290         } catch (NullPointerException JavaDoc npe) {
291             Exceptions.printStackTrace(npe);
292         }
293             
294         if (trans.isDataFlavorSupported(ExTransferable.multiFlavor)) {
295             // multi transferable, we must do extra work
296
try {
297                 MultiTransferObject obj = (MultiTransferObject) trans.getTransferData(ExTransferable.multiFlavor);
298                 int count = obj.getCount();
299                 Transferable JavaDoc[] t = new Transferable JavaDoc[count];
300                 PasteType[] p = new PasteType[count];
301                 PasteType pt = null;
302
303                 // extract default drop type of transferables
304
for (int i = 0; i < count; i++) {
305                     t[i] = obj.getTransferableAt(i);
306                     pt = node.getDropType(t[i], action, dropIndex);
307
308                     // return null if not accepted
309
if (pt == null) {
310                         return pt;
311                     }
312
313                     p[i] = pt;
314                 }
315
316                 // return new multi drop type
317
return new MultiPasteType(t, p);
318             } catch (UnsupportedFlavorException JavaDoc e) {
319                 // ignore and return null
320
} catch (IOException JavaDoc e) {
321                 // ignore and return null
322
}
323         }
324
325         return null;
326     }
327
328     /** Notifies user that the drop was not succesfull. */
329     static void dropNotSuccesfull() {
330         DialogDisplayer.getDefault().notify(
331             new Message(
332                 NbBundle.getBundle(TreeViewDropSupport.class).getString("MSG_NoPasteTypes"),
333                 NotifyDescriptor.WARNING_MESSAGE
334             )
335         );
336     }
337
338     /** If our clipboard is not found return the default system clipboard. */
339     private static Clipboard JavaDoc getClipboard() {
340         Clipboard JavaDoc c = (Clipboard JavaDoc) Lookup.getDefault().lookup(Clipboard JavaDoc.class);
341
342         if (c == null) {
343             c = Toolkit.getDefaultToolkit().getSystemClipboard();
344         }
345
346         return c;
347     }
348
349     /** Utility method created by Enno Sandner. Is it needed?
350      * I don't know (dstrupl).
351      */

352     static Node JavaDoc secureFindNode(Object JavaDoc o) {
353         assert o instanceof TreeNode JavaDoc : "Object " + o + " is instanceof TreeNode";
354         try {
355             return Visualizer.findNode(o);
356         } catch (ClassCastException JavaDoc e) {
357             e.printStackTrace();
358
359             return null;
360         }
361     }
362
363     /**
364      * Creates and populates popup as a result of
365      * dropping an item.
366      * @author Enno Sandner
367      */

368     static JPopupMenu JavaDoc createDropFinishPopup(final TreeSet JavaDoc pasteTypes) {
369         JPopupMenu JavaDoc menu = new JPopupMenu JavaDoc();
370
371         //System.arraycopy(pasteTypes, 0, pasteTypes_, 0, pasteTypes.length);
372
final JMenuItem JavaDoc[] items_ = new JMenuItem JavaDoc[pasteTypes.size()];
373
374         ActionListener JavaDoc aListener = new ActionListener JavaDoc() {
375                 public void actionPerformed(ActionEvent JavaDoc e) {
376                     JMenuItem JavaDoc source = (JMenuItem JavaDoc) e.getSource();
377
378                     final Iterator JavaDoc it = pasteTypes.iterator();
379
380                     for (int i = 0; it.hasNext(); i++) {
381                         PasteType action = (PasteType) it.next();
382
383                         if (items_[i].equals(source)) {
384                             DragDropUtilities.performPaste(action, null);
385                             invokePostDropRun();
386
387                             break;
388                         }
389                     }
390                 }
391             };
392
393         Iterator JavaDoc it = pasteTypes.iterator();
394
395         for (int i = 0; it.hasNext(); i++) {
396             items_[i] = new JMenuItem JavaDoc();
397             Mnemonics.setLocalizedText(items_[i], ((PasteType) it.next()).getName());
398             items_[i].addActionListener(aListener);
399             menu.add(items_[i]);
400         }
401
402         menu.addSeparator();
403
404         JMenuItem JavaDoc abortItem = new JMenuItem JavaDoc(NbBundle.getBundle(DragDropUtilities.class).getString("MSG_ABORT"));
405         menu.add(abortItem);
406
407         return menu;
408     }
409
410     /** Paste type used when in clipbopard is MultiTransferable */
411     static final class MultiPasteType extends PasteType {
412         // Attributes
413

414         /** Array of transferables */
415         Transferable JavaDoc[] t;
416
417         /** Array of paste types */
418         PasteType[] p;
419
420         // Operations
421

422         /** Constructs new MultiPasteType for the given
423         * transferables and paste types.*/

424         MultiPasteType(Transferable JavaDoc[] t, PasteType[] p) {
425             this.t = t;
426             this.p = p;
427         }
428
429         /** Performs the paste action.
430         * @return Transferable which should be inserted into the
431         * clipboard after paste action. It can be null, which means
432         * that clipboard content should be cleared.
433         */

434         public Transferable JavaDoc paste() throws IOException JavaDoc {
435             int size = p.length;
436             Transferable JavaDoc[] arr = new Transferable JavaDoc[size];
437
438             // perform paste for all source transferables
439
for (int i = 0; i < size; i++) {
440                 //System.out.println("Pasting #" + i); // NOI18N
441
arr[i] = p[i].paste();
442             }
443
444             return new Multi(arr);
445         }
446     }
447      // end of MultiPasteType
448
}
449
Popular Tags