KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > util > datatransfer > ExTransferable


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.util.datatransfer;
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.io.IOException JavaDoc;
26 import java.util.HashSet JavaDoc;
27 import java.util.LinkedHashMap JavaDoc;
28 import javax.swing.event.EventListenerList JavaDoc;
29 import org.openide.util.NbBundle;
30
31 /** Provides additional operations on
32 * a transferable.
33 *
34 * @author Jaroslav Tulach
35 */

36 public class ExTransferable extends Object JavaDoc implements Transferable JavaDoc {
37     /** An implementation of <code>Transferable</code> that contains no data. */
38     public static final Transferable JavaDoc EMPTY = new Empty();
39
40     /** Flavor for transfer of multiple objects.
41     */

42     public static final DataFlavor JavaDoc multiFlavor;
43     static {
44         try {
45             multiFlavor = new DataFlavor JavaDoc(
46                     "application/x-java-openide-multinode;class=org.openide.util.datatransfer.MultiTransferObject", // NOI18N
47
NbBundle.getBundle(ExTransferable.class).getString("transferFlavorsMultiFlavorName"),
48                     MultiTransferObject.class.getClassLoader());
49         } catch (ClassNotFoundException JavaDoc e) {
50             throw new AssertionError JavaDoc(e);
51         }
52     }
53
54     /** hash map that assigns objects to dataflavors (DataFlavor, Single) */
55     private LinkedHashMap JavaDoc<DataFlavor JavaDoc,Single> map;
56
57     /** listeners */
58     private EventListenerList JavaDoc listeners;
59
60     /** Creates new support.
61     * @param t transferable to to copy values from
62     * @param o clipobard owner (or null)
63     */

64     private ExTransferable(final Transferable JavaDoc t) {
65         map = new LinkedHashMap JavaDoc<DataFlavor JavaDoc,Single>();
66
67         final DataFlavor JavaDoc[] df = t.getTransferDataFlavors();
68
69         if (df != null) {
70             for (int i = 0; i < df.length; i++) {
71                 try {
72                     final int fi = i;
73                     map.put(
74                         df[i],
75                         new Single(df[i]) {
76                             public Object JavaDoc getData() throws IOException JavaDoc, UnsupportedFlavorException JavaDoc {
77                                 return t.getTransferData(df[fi]);
78                             }
79                         }
80                     );
81                 } catch (Exception JavaDoc ex) {
82                     // ignore if the data cannot be retrived
83
}
84             }
85         }
86     }
87
88     /** Add a new flavor with its data.
89     * @param single the single transferable to use
90     */

91     public void put(Single single) {
92         map.put(single.flavor, single);
93     }
94
95     /** Remove a flavor from the supported set.
96      * @param flavor the flavor to remove
97     */

98     public void remove(DataFlavor JavaDoc flavor) {
99         map.remove(flavor);
100     }
101
102     /* Get supported flavors.
103      * @return the flavors
104     */

105     public DataFlavor JavaDoc[] getTransferDataFlavors() {
106         return map.keySet().toArray(new DataFlavor JavaDoc[0]);
107     }
108
109     /* Is this flavor supported?
110     * @param flavor flavor to test
111     * @return <code>true</code> if this flavor is supported
112     */

113     public boolean isDataFlavorSupported(DataFlavor JavaDoc flavor) {
114         return map.containsKey(flavor);
115     }
116
117     /* Get the transferable data for this flavor.
118      * @param flavor the flavor
119      * @return the data
120      * @throws IOException currently not thrown
121      * @throws UnsupportedFlavorException if that flavor is not supported
122     */

123     public Object JavaDoc getTransferData(DataFlavor JavaDoc flavor) throws UnsupportedFlavorException JavaDoc, IOException JavaDoc {
124         Single o = map.get(flavor);
125
126         if (o == null) {
127             throw new UnsupportedFlavorException JavaDoc(flavor);
128         }
129
130         return o.getTransferData(flavor);
131     }
132
133     /** Method to create a new extended transferable from a plain transferable.
134     * If the given transferable is already <code>ExTransferable</code>, then it
135     * is returned as is.
136     * Otherwise the data is copied.
137     *
138     * @param t transferable to create support for
139     * @return extended transferable
140     */

141     public static ExTransferable create(Transferable JavaDoc t) {
142         // [PENDING] check should probably be: if (t.getClass() == ExTransferable.class)
143
// (in case for some weird reason someone subclasses ExTransferable)
144
if (t instanceof ExTransferable) {
145             return (ExTransferable) t;
146         }
147
148         return new ExTransferable(t);
149     }
150
151     /** Adds a listener to watch the life-cycle of this object.
152     *
153     * @param l the listener
154     */

155     public synchronized final void addTransferListener(TransferListener l) {
156         if (listeners == null) {
157             listeners = new EventListenerList JavaDoc();
158         }
159
160         listeners.add(TransferListener.class, l);
161     }
162
163     /** Removes a listener.
164     */

165     public synchronized final void removeTransferListener(TransferListener l) {
166         if (listeners != null) {
167             listeners.remove(TransferListener.class, l);
168         }
169     }
170
171     /** Fires notification to all listeners about
172     * accepting the drag.
173     * @param action one of java.awt.dnd.DnDConstants.ACTION_*
174     */

175     final void fireAccepted(int action) {
176         if (listeners == null) {
177             return;
178         }
179
180         Object JavaDoc[] arr = listeners.getListenerList();
181
182         for (int i = arr.length - 1; i >= 0; i -= 2) {
183             ((TransferListener) arr[i]).accepted(action);
184         }
185     }
186
187     /** Fires notification to all listeners about
188     * accepting the drag.
189     */

190     final void fireRejected() {
191         if (listeners == null) {
192             return;
193         }
194
195         Object JavaDoc[] arr = listeners.getListenerList();
196
197         for (int i = arr.length - 1; i >= 0; i -= 2) {
198             ((TransferListener) arr[i]).rejected();
199         }
200     }
201
202     /** Fires notification to all listeners about
203     * accepting the drag.
204     */

205     final void fireOwnershipLost() {
206         if (listeners == null) {
207             return;
208         }
209
210         Object JavaDoc[] arr = listeners.getListenerList();
211
212         for (int i = arr.length - 1; i >= 0; i -= 2) {
213             ((TransferListener) arr[i]).ownershipLost();
214         }
215     }
216
217     /** Support for transferable owner with only one data flavor.
218     * Subclasses need only implement {@link #getData}.
219     */

220     public static abstract class Single extends Object JavaDoc implements Transferable JavaDoc {
221         /** the supported data flavor */
222         private DataFlavor JavaDoc flavor;
223
224         /** Constructor.
225         * @param flavor flavor of the data
226         */

227         public Single(DataFlavor JavaDoc flavor) {
228             this.flavor = flavor;
229         }
230
231         /* Flavors that are supported.
232         * @return array with <CODE>contextFlavor</CODE>
233         * @see TransferFlavors.contextFlavor
234         */

235         public DataFlavor JavaDoc[] getTransferDataFlavors() {
236             return new DataFlavor JavaDoc[] { flavor };
237         }
238
239         /* Is the flavor supported?
240         * @param flavor flavor to test
241         * @return true if this flavor is supported
242         */

243         public boolean isDataFlavorSupported(DataFlavor JavaDoc flavor) {
244             return this.flavor.equals(flavor);
245         }
246
247         /* Creates transferable data for this flavor.
248         */

249         public Object JavaDoc getTransferData(DataFlavor JavaDoc flavor)
250         throws UnsupportedFlavorException JavaDoc, IOException JavaDoc {
251             if (!this.flavor.equals(flavor)) {
252                 throw new UnsupportedFlavorException JavaDoc(flavor);
253             }
254
255             return getData();
256         }
257
258         /** Abstract method to override to provide the right data for this
259         * transferable.
260         *
261         * @return the data
262         * @throws IOException when an I/O error occurs
263         * @throws UnsupportedFlavorException if the flavor is not supported
264         */

265         protected abstract Object JavaDoc getData() throws IOException JavaDoc, UnsupportedFlavorException JavaDoc;
266     }
267
268     /** Transferable object for multiple transfer.
269      * It allows several types of data
270     * to be combined into one clipboard element.
271     *
272     * @author Jaroslav Tulach
273     */

274     public static class Multi extends Object JavaDoc implements Transferable JavaDoc {
275         /** supported flavors list */
276         private static final DataFlavor JavaDoc[] flavorList = { multiFlavor };
277
278         /** object that is about to be return as result of transfer */
279         private MultiTransferObject transferObject;
280
281         /** Constructor taking a list of <code>Transferable</code> objects.
282          *
283          * @param trans array of transferable objects
284          */

285         public Multi(Transferable JavaDoc[] trans) {
286             transferObject = new TransferObjectImpl(trans);
287         }
288
289         /** Get supported flavors.
290          * @return only one flavor, {@link #multiFlavor}
291         */

292         public DataFlavor JavaDoc[] getTransferDataFlavors() {
293             return flavorList;
294         }
295
296         /** Is this flavor supported?
297          * @param flavor the flavor
298         * @return <code>true</code> only if the flavor is {@link #multiFlavor}
299         */

300         public boolean isDataFlavorSupported(DataFlavor JavaDoc flavor) {
301             return flavor.equals(multiFlavor);
302         }
303
304         /** Get transfer data.
305          * @param flavor the flavor ({@link #multiFlavor})
306         * @return {@link MultiTransferObject} that represents data in this object
307         * @exception UnsupportedFlavorException when the flavor is not supported
308         * @exception IOException when it is not possible to read data
309         */

310         public Object JavaDoc getTransferData(DataFlavor JavaDoc flavor)
311         throws UnsupportedFlavorException JavaDoc, IOException JavaDoc {
312             if (!isDataFlavorSupported(flavor)) {
313                 throw new UnsupportedFlavorException JavaDoc(flavor);
314             }
315
316             return transferObject;
317         }
318
319         /** Class implementing MultiTransferObject interface. */
320         static class TransferObjectImpl implements MultiTransferObject {
321             /** transferable objects */
322             private Transferable JavaDoc[] trans;
323
324             /** Creates new object from transferable objects.
325             * @param trans array of transferable objects
326             */

327             public TransferObjectImpl(Transferable JavaDoc[] trans) {
328                 this.trans = trans;
329             }
330
331             /** Number of transfered elements.
332             * @return number of elements
333             */

334             public int getCount() {
335                 return trans.length;
336             }
337
338             /** @return Transferable at the specific index */
339             public Transferable JavaDoc getTransferableAt(int index) {
340                 return trans[index];
341             }
342
343             /** Test whether data flavor is supported by index-th item.
344             *
345             * @param index the index of
346             * @param flavor flavor to test
347             * @return <CODE>true</CODE> if flavor is supported by all elements
348             */

349             public boolean isDataFlavorSupported(int index, DataFlavor JavaDoc flavor) {
350                 try {
351                     return trans[index].isDataFlavorSupported(flavor);
352                 } catch (Exception JavaDoc e) {
353                     return false;
354
355                     // patch to get the Netbeans start under Solaris
356
// [PENDINGbeta]
357
}
358             }
359
360             /** Test whether each transfered item supports at least one of these
361             * flavors. Each item can support different flavor.
362             * @param array array of flavors
363             */

364             public boolean areDataFlavorsSupported(DataFlavor JavaDoc[] array) {
365                 HashSet JavaDoc<DataFlavor JavaDoc> flav = new HashSet JavaDoc<DataFlavor JavaDoc>();
366
367                 for (int i = 0; i < array.length; i++) {
368                     flav.add(array[i]);
369                 }
370
371
372 // cycles through all transferable objects and scans their content
373
// to find out if each supports at least one requested flavor
374
outer:
375                 for (int i = 0; i < trans.length; i++) {
376                     // insert all flavors of the first object into array
377
DataFlavor JavaDoc[] flavors = trans[i].getTransferDataFlavors();
378
379                     if (flavors == null) {
380                         return false;
381                     }
382
383                     // loop through rest of Transferable objects
384
for (int j = 0; j < flavors.length; j++) {
385                         if (flav.contains(flavors[j])) {
386                             // this flavor is supported
387
continue outer;
388                         }
389                     }
390
391                     // for this transferable no flavor is supported
392
return false;
393                 }
394
395                 return true;
396             }
397
398             /** Gets list of all supported flavors for i-th element.
399             * @param i the element to find flavors for
400             * @return array of supported flavors
401             */

402             public DataFlavor JavaDoc[] getTransferDataFlavors(int i) {
403                 return trans[i].getTransferDataFlavors();
404             }
405
406             /**
407             * @param indx index of element to work with
408             * @param flavor one needs to obtain
409             * @return object for the flavor of the i-th element
410             */

411             public Object JavaDoc getTransferData(int indx, DataFlavor JavaDoc flavor)
412             throws UnsupportedFlavorException JavaDoc, IOException JavaDoc {
413                 return trans[indx].getTransferData(flavor);
414             }
415
416             /** Compute common flavors.
417             * @param t array of transferable objects
418             * @return array of common flavors
419             * /
420             private static DataFlavor[] computeCommonFlavors (Transferable[] t) {
421                 if (t.length == 0) {
422                     // no flavor is supported => return empty array
423                     return new DataFlavor[] { };
424                 }
425
426                 // insert all flavors of the first object into array
427                 DataFlavor[] flavors = t[0].getTransferDataFlavors ();
428                 // number of non null elements in flavors array
429                 int flavorsCount = (flavors == null)? 0 : flavors.length;
430                 int flavorsLength = flavorsCount; // non-changing length of the original flavors array
431
432                 // loop through rest of Transferable objects
433                 for (int i = 1; i < t.length; i++) {
434                     // loop through array
435                     for (int j = 0; j < flavorsLength; j++) {
436                         // if the flavor is not supported
437                         boolean supported = false;
438                         try {
439                             supported = t[i].isDataFlavorSupported (flavors[j]);
440                         } catch (Exception e) {
441                             // patch to get the Netbeans start under Solaris
442                             // [PENDINGbeta]
443                         }
444                         if (flavors[j] != null && !supported) {
445                             // then clear it
446                             flavors[j] = null;
447                             flavorsCount--;
448                         }
449                     }
450                 }
451
452                 // create resulting array
453                 DataFlavor[] result = new DataFlavor[flavorsLength];
454                 for (int i = 0, j = 0; i < flavorsLength; i++) {
455                     if (flavors[i] != null) {
456                         // add it to the result
457                         result[j++] = flavors[i];
458                     }
459                 }
460
461                 return result;
462             }
463             */

464         }
465     }
466
467     /** TransferableOwnerEmpty is TransferableOwner that contains no data.
468     *
469     * @author Jaroslav Tulach
470     */

471     private static class Empty extends Object JavaDoc implements Transferable JavaDoc {
472         /** Package private constructor to allow only one instance from TransferableOwner.
473         */

474         Empty() {
475         }
476
477         /** Flavors that are supported.
478         * @return empty array
479         */

480         public DataFlavor JavaDoc[] getTransferDataFlavors() {
481             return new DataFlavor JavaDoc[] { };
482         }
483
484         /** Does not support any flavor
485         * @param flavor flavor to test
486         * @return false
487         */

488         public boolean isDataFlavorSupported(DataFlavor JavaDoc flavor) {
489             return false;
490         }
491
492         /** Creates transferable data for this flavor.
493         * @exception UnsupportedFlavorException does not support any flavor
494         */

495         public Object JavaDoc getTransferData(DataFlavor JavaDoc flavor)
496         throws UnsupportedFlavorException JavaDoc, IOException JavaDoc {
497             throw new UnsupportedFlavorException JavaDoc(flavor);
498         }
499     }
500 }
501
Popular Tags