KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > nodes > NodeTransfer


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.nodes;
21
22 import java.awt.datatransfer.DataFlavor JavaDoc;
23 import java.awt.datatransfer.Transferable JavaDoc;
24 import java.awt.datatransfer.UnsupportedFlavorException JavaDoc;
25 import java.awt.dnd.DnDConstants JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.text.MessageFormat JavaDoc;
28 import java.util.logging.Level JavaDoc;
29 import java.util.logging.Logger JavaDoc;
30 import org.openide.util.datatransfer.ExTransferable;
31 import org.openide.util.datatransfer.MultiTransferObject;
32 import org.openide.util.datatransfer.PasteType;
33
34 /** Class that contains specific datatransfer flavors and methods to work with
35 * nodes. There are flavors to allow a node
36 * to be copied or cut, and to decide its paste types.
37 * <p>This is a dummy utility class--no instances are possible.
38 *
39 * @author Jaroslav Tulach
40 */

41 public abstract class NodeTransfer extends Object JavaDoc {
42     /** Constants for drag-n-drop operations.
43     * Are exactly the same as constants
44     * in {@link DnDConstants}.
45     */

46     public static final int DND_NONE = DnDConstants.ACTION_NONE;
47     public static final int DND_COPY = DnDConstants.ACTION_COPY;
48     public static final int DND_MOVE = DnDConstants.ACTION_MOVE;
49     public static final int DND_COPY_OR_MOVE = DnDConstants.ACTION_COPY | DnDConstants.ACTION_MOVE;
50     public static final int DND_LINK = DnDConstants.ACTION_LINK;
51     public static final int DND_REFERENCE = DnDConstants.ACTION_LINK;
52
53     /** Constant indicating copying to the clipboard.
54     * Equal to {@link #DND_COPY}, because
55     * copy to clipboard and d'n'd copy should be the same.
56     */

57     public static final int CLIPBOARD_COPY = DND_COPY;
58
59     /** Constant indicating cutting to the clipboard.
60     */

61     public static final int CLIPBOARD_CUT = 0x04;
62
63     /** Generic mask for copying nodes (do not destroy the original).
64     * Equal to {@link #CLIPBOARD_COPY} or {@link #DND_COPY}.
65     */

66     public static final int COPY = CLIPBOARD_COPY | DND_COPY;
67
68     /** Generic mask for moving nodes (destroy the original).
69     * Equal to {@link #CLIPBOARD_CUT} or {@link #DND_MOVE}.
70     */

71     public static final int MOVE = CLIPBOARD_CUT | DND_MOVE;
72
73     /** Flavor for representation class {@link NodeTransfer.Paste}.
74     * Provides methods for obtaining a set of {@link PasteType}s when
75     * the target node is known.
76     */

77     private static final DataFlavor JavaDoc nodePasteFlavor;
78     static {
79         try {
80             nodePasteFlavor = new DataFlavor JavaDoc(
81                     "application/x-java-openide-nodepaste;class=org.openide.nodes.Node", // NOI18N
82
Node.getString("LBL_nodePasteFlavor"),
83                     Node.class.getClassLoader());
84         } catch (ClassNotFoundException JavaDoc e) {
85             throw new AssertionError JavaDoc(e);
86         }
87     }
88
89     /** message format to create and parse the mimetype
90     */

91     private static MessageFormat JavaDoc dndMimeType = new MessageFormat JavaDoc(
92             "application/x-java-openide-nodednd;class=org.openide.nodes.Node;mask={0}" // NOI18N
93
);
94
95     private NodeTransfer() {
96     }
97
98     /** Creates data flavor for given mask of dnd actions.
99     * @param actions any mask of dnd constants DND_* and CLIPBOARD_*
100     */

101     private static DataFlavor JavaDoc createDndFlavor(int actions) {
102         try {
103             return new DataFlavor JavaDoc(dndMimeType.format(new Object JavaDoc[] { new Integer JavaDoc(actions) }),
104                     null, Node.class.getClassLoader());
105         } catch (ClassNotFoundException JavaDoc cnfE) {
106             throw (IllegalStateException JavaDoc) new IllegalStateException JavaDoc().initCause(cnfE);
107         }
108     }
109
110     /** Creates transferable that represents a node operation, such as cut-to-clipboard.
111     * The transferable will be recognizable by {@link #node}, {@link #nodes}, and {@link #cookie}.
112     *
113     * @param n the node to create a transferable for
114     * @param actions the action performed on the node
115     * @return the transferable
116     */

117     public static ExTransferable.Single transferable(final Node n, int actions) {
118         return new ExTransferable.Single(createDndFlavor(actions)) {
119                 public Object JavaDoc getData() {
120                     return n;
121                 }
122             };
123     }
124
125     /** Obtain a node from a transferable.
126     * Probes the transferable in case it includes a flavor corresponding
127     * to a node operation (which you must specify a mask for).
128     *
129     * @param t transferable
130     * @param action one of the <code>DND_*</code> or <code>CLIPBOARD_*</code> constants
131     * @return the node or <code>null</code>
132     */

133     public static Node node(Transferable JavaDoc t, int action) {
134         DataFlavor JavaDoc[] flavors = t.getTransferDataFlavors();
135
136         if (flavors == null) {
137             return null;
138         }
139
140         int len = flavors.length;
141
142         String JavaDoc subtype = "x-java-openide-nodednd"; // NOI18N
143
String JavaDoc primary = "application"; // NOI18N
144
String JavaDoc mask = "mask"; // NOI18N
145

146         for (int i = 0; i < len; i++) {
147             DataFlavor JavaDoc df = flavors[i];
148
149             if (df.getSubType().equals(subtype) && df.getPrimaryType().equals(primary)) {
150                 try {
151                     int m = Integer.valueOf(df.getParameter(mask)).intValue();
152
153                     if ((m & action) != 0) {
154                         // found the node
155
return (Node) t.getTransferData(df);
156                     }
157                 } catch (NumberFormatException JavaDoc nfe) {
158                     maybeReportException(nfe);
159                 } catch (ClassCastException JavaDoc cce) {
160                     maybeReportException(cce);
161                 } catch (IOException JavaDoc ioe) {
162                     maybeReportException(ioe);
163                 } catch (UnsupportedFlavorException JavaDoc ufe) {
164                     maybeReportException(ufe);
165                 }
166             }
167         }
168
169         return null;
170     }
171
172     /** Obtain a list of nodes from a transferable.
173     * If there is only a single node in the transferable, this will just return a singleton
174     * array like {@link #node}.
175     * If there is a {@link ExTransferable#multiFlavor multiple transfer} (of at least one element),
176     * each element of which
177     * contains a node, then an array of these will be returned.
178     * If neither of these things is true, <code>null</code> will be returned.
179     * <p>This is a convenience method intended for those who wish to specially support pastes
180     * of multiple nodes at once. (By default, an explorer will
181     * fall back to presenting each component of a multiple-item transferable separately when checking for paste
182     * types on a target node, so if you have only one paste type and it makes no difference whether all of the nodes
183     * are pasted together or separately, you can just use {@link #node}.)
184     * <p>If you wish to test for cookies, you should do so manually
185     * according to your specific logic.
186     * @param t the transferable to probe
187     * @param action a DnD or clipboard constant
188     * @return a non-empty array of nodes, or <code>null</code>
189     */

190     public static Node[] nodes(Transferable JavaDoc t, int action) {
191         try {
192             if (t.isDataFlavorSupported(ExTransferable.multiFlavor)) {
193                 MultiTransferObject mto = (MultiTransferObject) t.getTransferData(ExTransferable.multiFlavor);
194                 int count = mto.getCount();
195                 Node[] ns = new Node[count];
196                 boolean ok = true;
197
198                 for (int i = 0; i < count; i++) {
199                     Node n = node(mto.getTransferableAt(i), action);
200
201                     if (n == null) {
202                         ok = false;
203
204                         break;
205                     } else {
206                         ns[i] = n;
207                     }
208                 }
209
210                 if (ok && (count > 0)) {
211                     return ns;
212                 }
213             } else {
214                 Node n = node(t, action);
215
216                 if (n != null) {
217                     return new Node[] { n };
218                 }
219             }
220         } catch (ClassCastException JavaDoc cce) {
221             maybeReportException(cce);
222         } catch (IOException JavaDoc ioe) {
223             maybeReportException(ioe);
224         } catch (UnsupportedFlavorException JavaDoc ufe) {
225             maybeReportException(ufe);
226         }
227
228         return null;
229     }
230
231     /** Obtain a cookie instance from the copied node in a transferable.
232     * <P>
233     * First of all it checks whether the given transferable contains
234     * a node and then asks for the cookie.
235     * <p>If you wish to specially support multiple-node transfers, please use {@link #nodes}
236     * and manually check for the desired combination of cookies.
237     *
238     * @param t transferable to check in
239     * @param cookie cookie representation class to look for
240     * @param action the action which was used to store the node
241     *
242     * @return cookie or <code>null</code> if it does not exist
243     */

244     public static <T extends Node.Cookie> T cookie(Transferable JavaDoc t, int action, Class JavaDoc<T> cookie) {
245         Node n = node(t, action);
246
247         return (n == null) ? null : n.getCookie(cookie);
248     }
249
250     /** Creates transfer object that is used to carry an intelligent
251     * paste source through transferable or clipboard.
252     * {@link #findPaste} can retrieve it.
253     * @param paste the intelligent source of paste types
254     * @return the transferable
255     */

256     public static ExTransferable.Single createPaste(final Paste paste) {
257         return new ExTransferable.Single(nodePasteFlavor) {
258                 public Object JavaDoc getData() {
259                     return paste;
260                 }
261             };
262     }
263
264     /** Find an intelligent source of paste types in a transferable.
265     * Note that {@link AbstractNode#createPasteTypes} looks for this
266     * by default, so cut/copied nodes may specify how they may be pasted
267     * to some external node target.
268     * @param t the transferable to test
269     * @return the intelligent source or <code>null</code> if none is in the transferable
270     */

271     public static Paste findPaste(Transferable JavaDoc t) {
272         try {
273             if (t.isDataFlavorSupported(nodePasteFlavor)) {
274                 return (Paste) t.getTransferData(nodePasteFlavor);
275             }
276         } catch (ClassCastException JavaDoc cce) {
277             maybeReportException(cce);
278         } catch (IOException JavaDoc ioe) {
279             maybeReportException(ioe);
280         } catch (UnsupportedFlavorException JavaDoc ufe) {
281             maybeReportException(ufe);
282         }
283
284         return null;
285     }
286
287     /** Print a stack trace if debugging is on.
288     * Used for exceptions that could occur when probing transferables,
289     * which should not interrupt the probing with an error, but
290     * indicate a bug elsewhere and should be reported somehow.
291     * @param e the exception
292     */

293     private static void maybeReportException(Exception JavaDoc e) {
294         Logger.getLogger(NodeTransfer.class.getName()).log(Level.WARNING, null, e);
295
296         // else do nothing
297
}
298
299     /** An intelligent source of paste types (ways how to paste)
300     * for a target node.
301     * <P>
302     * Each node should check for this
303     * type in a paste operation to allow anyone to insert something
304     * into it.
305     * <P>
306     * Sample example of implementation of {@link Node#getPasteTypes}:
307     * <p><code><PRE>
308     * public PasteType[] getPasteTypes (Transferable t) {
309     * NodeTransfer.Paste p = (NodeTransfer.Paste)t.getTransferData (
310     * NodeTransfer.nodePasteFlavor
311     * );
312     * return p.types (this);
313     * }
314     * </PRE></code>
315     */

316     public interface Paste {
317         /** Method that checks the type of target node and can
318         * decide which paste types it supports.
319         *
320         * @param target the target node
321         * @return array of paste types that are valid for such a target node
322         */

323         public PasteType[] types(Node target);
324     }
325 }
326
Popular Tags