OSDN Git Service

2004-11-30 Thomas Fitzsimmons <fitzsim@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / java / awt / datatransfer / DataFlavor.java
1 /* DataFlavor.java -- A type of data to transfer via the clipboard.
2    Copyright (C) 1999, 2001, 2004 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package java.awt.datatransfer;
40
41 import java.io.ByteArrayInputStream;
42 import java.io.IOException;
43 import java.io.InputStream;
44 import java.io.InputStreamReader;
45 import java.io.ObjectInput;
46 import java.io.ObjectOutput;
47 import java.io.Reader;
48 import java.io.StringReader;
49 import java.io.UnsupportedEncodingException;
50 import java.nio.ByteBuffer;
51 import java.nio.CharBuffer;
52
53 /**
54  * This class represents a particular data format used for transferring
55  * data via the clipboard.
56  *
57  * @author Aaron M. Renn (arenn@urbanophile.com)
58  */
59 public class DataFlavor implements java.io.Externalizable, Cloneable
60 {
61   static final long serialVersionUID = 8367026044764648243L;
62
63   // FIXME: Serialization: Need to write methods for.
64
65 /**
66  * This is the data flavor used for tranferring plain text.  The MIME
67  * type is "text/plain; charset=unicode".  The representation class
68  * is <code>java.io.InputStream</code>.
69  *
70  * @deprecated The charset unicode is platform specific and InputStream
71  * deals with bytes not chars. Use <code>getRederForText()</code>.
72  */
73 public static final DataFlavor plainTextFlavor;
74
75 /**
76  * This is the data flavor used for transferring Java strings.  The
77  * MIME type is "application/x-java-serialized-object" and the 
78  * representation class is <code>java.lang.String</code>.
79  */
80 public static final DataFlavor stringFlavor;
81
82 /**
83  * This is a data flavor used for transferring lists of files.  The
84  * representation type is a <code>java.util.List</code>, with each element of 
85  * the list being a <code>java.io.File</code>.
86  */
87 public static final DataFlavor javaFileListFlavor;
88
89 /**
90  * This is an image flavor used for transferring images.  The
91  * representation type is a <code>java.awt.Image</code>.
92  */
93 public static final DataFlavor imageFlavor;
94
95 /**
96  * This is the MIME type used for transferring a serialized object.
97  * The representation class is the type of object be deserialized.
98  */
99 public static final String javaSerializedObjectMimeType =
100   "application/x-java-serialized-object";
101
102 /**
103  * This is the MIME type used to transfer a Java object reference within
104  * the same JVM.  The representation class is the class of the object
105  * being transferred.
106  */
107 public static final String javaJVMLocalObjectMimeType =
108   "application/x-java-jvm-local-objectref";
109
110 /**
111  * This is the MIME type used to transfer a link to a remote object.
112  * The representation class is the type of object being linked to.
113  */
114 public static final String javaRemoteObjectMimeType =
115   "application/x-java-remote-object";
116
117 static
118 {
119   plainTextFlavor
120       = new DataFlavor(java.io.InputStream.class,
121                        "text/plain; charset=unicode",
122                        "plain unicode text");
123
124   stringFlavor
125       = new DataFlavor(java.lang.String.class,
126                        "Java Unicode String");
127
128   javaFileListFlavor
129       = new DataFlavor(java.util.List.class,
130                        "Java File List");
131
132   // javaFileListFlavor.mimeType = "application/x-java-file-list";
133
134   imageFlavor
135       = new DataFlavor(java.awt.Image.class,
136                        "Java Image");
137 }
138
139 /*************************************************************************/
140
141 /*
142  * Instance Variables
143  */
144
145 // The MIME type for this flavor
146 private final String mimeType;
147
148 // The representation class for this flavor
149 private final Class representationClass;
150
151 // The human readable name of this flavor
152 private String humanPresentableName;
153
154 /*************************************************************************/
155
156 /*
157  * Static Methods
158  */
159
160 /**
161  * This method attempts to load the named class.  The following class
162  * loaders are searched in order: the bootstrap class loader, the
163  * system class loader, the context class loader (if it exists), and
164  * the specified fallback class loader.
165  *
166  * @param className The name of the class to load.
167  * @param classLoader The class loader to use if all others fail, which
168  * may be <code>null</code>.
169  *
170  * @exception ClassNotFoundException If the class cannot be loaded.
171  */
172 protected static final Class
173 tryToLoadClass(String className, ClassLoader classLoader)
174                throws ClassNotFoundException
175 {
176   try
177     {
178       return(Class.forName(className));
179     }
180   catch(Exception e) { ; }
181   // Commented out for Java 1.1
182   /*
183   try
184     {
185       return(className.getClass().getClassLoader().findClass(className));
186     }
187   catch(Exception e) { ; }
188
189   try
190     {
191       return(ClassLoader.getSystemClassLoader().findClass(className));
192     }
193   catch(Exception e) { ; }
194   */
195
196   // FIXME: What is the context class loader?
197   /*
198   try
199     {
200     }
201   catch(Exception e) { ; }
202   */
203
204   if (classLoader != null)
205     return(classLoader.loadClass(className));
206   else
207     throw new ClassNotFoundException(className);
208 }
209
210 /*************************************************************************/
211
212 /*
213  * Constructors
214  */
215
216 /**
217  * Empty public constructor needed for externalization.
218  * Should not be used for normal instantiation.
219  */
220 public
221 DataFlavor()
222 {
223     mimeType = null;
224     representationClass = null;
225     humanPresentableName = null;
226 }
227
228 /*************************************************************************/
229
230 /**
231  * Private constructor.
232  */
233 private
234 DataFlavor(Class representationClass,
235            String mimeType,
236            String humanPresentableName)
237 {
238     this.representationClass = representationClass;
239     this.mimeType = mimeType;
240     if (humanPresentableName != null)
241         this.humanPresentableName = humanPresentableName;
242     else
243         this.humanPresentableName = mimeType;
244 }
245
246 /*************************************************************************/
247
248 /**
249  * Initializes a new instance of <code>DataFlavor</code>.  The class
250  * and human readable name are specified, the MIME type will be
251  * "application/x-java-serialized-object". If the human readable name
252  * is not specified (<code>null</code>) then the human readable name
253  * will be the same as the MIME type.
254  *
255  * @param representationClass The representation class for this object.
256  * @param humanPresentableName The display name of the object.
257  */
258 public
259 DataFlavor(Class representationClass, String humanPresentableName)
260 {
261     this(representationClass,
262        "application/x-java-serialized-object"
263        + "; class="
264        + representationClass.getName(),
265        humanPresentableName);
266 }
267
268 /*************************************************************************/
269
270 /**
271  * Initializes a new instance of <code>DataFlavor</code> with the
272  * specified MIME type and description.  If the MIME type has a
273  * "class=&lt;rep class&gt;" parameter then the representation class will
274  * be the class name specified. Otherwise the class defaults to
275  * <code>java.io.InputStream</code>. If the human readable name
276  * is not specified (<code>null</code>) then the human readable name
277  * will be the same as the MIME type.
278  *
279  * @param mimeType The MIME type for this flavor.
280  * @param humanPresentableName The display name of this flavor.
281  * @param classLoader The class loader for finding classes if the default
282  * class loaders do not work.
283  *
284  * @exception IllegalArgumentException If the representation class
285  * specified cannot be loaded.
286  * @exception ClassNotFoundException If the class is not loaded.
287  */
288 public
289 DataFlavor(String mimeType, String humanPresentableName, 
290            ClassLoader classLoader) throws ClassNotFoundException
291 {
292   this(getRepresentationClassFromMime(mimeType, classLoader),
293        mimeType, humanPresentableName);
294 }
295
296 private static Class
297 getRepresentationClassFromMime(String mimeString, ClassLoader classLoader)
298 {
299   String classname = getParameter("class", mimeString);
300   if (classname != null)
301     {
302       try
303         {
304           return tryToLoadClass(classname, classLoader);
305         }
306       catch(Exception e)
307         {
308           throw new IllegalArgumentException("classname: " + e.getMessage());
309         }
310     }
311   else
312     {
313       return java.io.InputStream.class;
314     }
315 }
316
317 /*************************************************************************/
318
319 /**
320  * Initializes a new instance of <code>DataFlavor</code> with the
321  * specified MIME type and description.  If the MIME type has a
322  * "class=&lt;rep class&gt;" parameter then the representation class will
323  * be the class name specified. Otherwise the class defaults to
324  * <code>java.io.InputStream</code>. If the human readable name
325  * is not specified (<code>null</code>) then the human readable name
326  * will be the same as the MIME type. This is the same as calling
327  * <code>new DataFlavor(mimeType, humanPresentableName, null)</code>.
328  *
329  * @param mimeType The MIME type for this flavor.
330  * @param humanPresentableName The display name of this flavor.
331  *
332  * @exception IllegalArgumentException If the representation class
333  * specified cannot be loaded.
334  */
335 public
336 DataFlavor(String mimeType, String humanPresentableName)
337 {
338   this (getRepresentationClassFromMime (mimeType, null), humanPresentableName);
339 }
340
341 /*************************************************************************/
342
343 /**
344  * Initializes a new instance of <code>DataFlavor</code> with the specified
345  * MIME type.  This type can have a "class=" parameter to specify the
346  * representation class, and then the class must exist or an exception will
347  * be thrown. If there is no "class=" parameter then the representation class
348  * will be <code>java.io.InputStream</code>. This is the same as calling
349  * <code>new DataFlavor(mimeType, null)</code>.
350  *
351  * @param mimeType The MIME type for this flavor.
352  *
353  * @exception IllegalArgumentException If a class is not specified in
354  * the MIME type.
355  * @exception ClassNotFoundException If the class cannot be loaded.
356  */
357 public
358 DataFlavor(String mimeType) throws ClassNotFoundException
359 {
360   this(mimeType, null);
361 }
362
363 /*************************************************************************/
364
365 /**
366  * Returns the MIME type of this flavor.
367  *
368  * @return The MIME type for this flavor.
369  */
370 public String
371 getMimeType()
372 {
373   return(mimeType);
374 }
375
376 /*************************************************************************/
377
378 /**
379  * Returns the representation class for this flavor.
380  *
381  * @return The representation class for this flavor.
382  */
383 public Class
384 getRepresentationClass()
385 {
386   return(representationClass);
387 }
388
389 /*************************************************************************/
390
391 /**
392  * Returns the human presentable name for this flavor.
393  *
394  * @return The human presentable name for this flavor.
395  */
396 public String
397 getHumanPresentableName()
398 {
399   return(humanPresentableName);
400
401
402 /*************************************************************************/
403
404 /**
405  * Returns the primary MIME type for this flavor.
406  *
407  * @return The primary MIME type for this flavor.
408  */
409 public String
410 getPrimaryType()
411 {
412   int idx = mimeType.indexOf("/");
413   if (idx == -1)
414     return(mimeType);
415
416   return(mimeType.substring(0, idx));
417 }
418
419 /*************************************************************************/
420
421 /**
422  * Returns the MIME subtype for this flavor.
423  *
424  * @return The MIME subtype for this flavor.
425  */
426 public String
427 getSubType()
428 {
429   int idx = mimeType.indexOf("/");
430   if (idx == -1)
431     return("");
432
433   String subtype = mimeType.substring(idx + 1);
434
435   idx = subtype.indexOf(" ");
436   if (idx == -1)
437     return(subtype);
438   else
439     return(subtype.substring(0, idx));
440 }
441
442 /*************************************************************************/
443
444 /**
445  * Returns the value of the named MIME type parameter, or <code>null</code>
446  * if the parameter does not exist. Given the parameter name and the mime
447  * string.
448  *
449  * @param paramName The name of the parameter.
450  * @param mimeString The mime string from where the name should be found.
451  *
452  * @return The value of the parameter or null.
453  */
454 private static String
455 getParameter(String paramName, String mimeString)
456 {
457   int idx = mimeString.indexOf(paramName + "=");
458   if (idx == -1)
459     return(null);
460
461   String value = mimeString.substring(idx + paramName.length() + 1);
462
463   idx = value.indexOf(" ");
464   if (idx == -1)
465     return(value);
466   else
467     return(value.substring(0, idx));
468 }
469
470 /*************************************************************************/
471
472 /**
473  * Returns the value of the named MIME type parameter, or <code>null</code>
474  * if the parameter does not exist.
475  *
476  * @param paramName The name of the paramter.
477  *
478  * @return The value of the parameter.
479  */
480 public String
481 getParameter(String paramName)
482 {
483   return getParameter(paramName, mimeType);
484 }
485
486 /*************************************************************************/
487
488 /**
489  * Sets the human presentable name to the specified value.
490  *
491  * @param humanPresentableName The new display name.
492  */
493 public void
494 setHumanPresentableName(String humanPresentableName)
495 {
496   this.humanPresentableName = humanPresentableName;
497 }
498
499 /*************************************************************************/
500
501 /**
502  * Tests the MIME type of this object for equality against the specified
503  * MIME type.
504  *
505  * @param mimeType The MIME type to test against.
506  *
507  * @return <code>true</code> if the MIME type is equal to this object's
508  * MIME type, <code>false</code> otherwise.
509  *
510  * @exception NullPointerException If mimeType is null.
511  */
512 public boolean
513 isMimeTypeEqual(String mimeType)
514 {
515   // FIXME: Need to handle default attributes and parameters
516
517   return(this.mimeType.equals(mimeType));
518 }
519
520 /*************************************************************************/
521
522 /**
523  * Tests the MIME type of this object for equality against the specified
524  * data flavor's MIME type
525  *
526  * @param flavor The flavor to test against.
527  *
528  * @return <code>true</code> if the flavor's MIME type is equal to this 
529  * object's MIME type, <code>false</code> otherwise.
530  */
531 public final boolean
532 isMimeTypeEqual(DataFlavor flavor)
533 {
534   return(isMimeTypeEqual(flavor.getMimeType()));
535 }
536
537 /*************************************************************************/
538
539 /**
540  * Tests whether or not this flavor represents a serialized object.
541  *
542  * @return <code>true</code> if this flavor represents a serialized
543  * object, <code>false</code> otherwise.
544  */
545 public boolean
546 isMimeTypeSerializedObject()
547 {
548   return(mimeType.startsWith(javaSerializedObjectMimeType));
549 }
550
551 /*************************************************************************/
552
553 /**
554  * Tests whether or not this flavor has a representation class of
555  * <code>java.io.InputStream</code>.
556  *
557  * @return <code>true</code> if the representation class of this flavor
558  * is <code>java.io.InputStream</code>, <code>false</code> otherwise.
559  */
560 public boolean
561 isRepresentationClassInputStream()
562 {
563   return(representationClass.getName().equals("java.io.InputStream"));
564 }
565
566 /*************************************************************************/
567
568 /**
569  * Tests whether the representation class for this flavor is
570  * serializable.
571  *
572  * @return <code>true</code> if the representation class is serializable,
573  * <code>false</code> otherwise.
574  */
575 public boolean
576 isRepresentationClassSerializable()
577 {
578   Class[] interfaces = representationClass.getInterfaces();
579
580   int i = 0;
581   while (i < interfaces.length)
582     {
583       if (interfaces[i].getName().equals("java.io.Serializable"))
584         return(true);
585       ++i;
586     }
587
588   return(false);
589 }
590
591 /*************************************************************************/
592
593 /**
594  * Tests whether the representation class for his flavor is remote.
595  *
596  * @return <code>true</code> if the representation class is remote,
597  * <code>false</code> otherwise.
598  */
599 public boolean
600 isRepresentationClassRemote()
601 {
602   // FIXME: Implement
603   throw new RuntimeException("Not implemented");
604 }
605
606 /*************************************************************************/
607
608 /**
609  * Tests whether or not this flavor represents a serialized object.
610  *
611  * @return <code>true</code> if this flavor represents a serialized
612  * object, <code>false</code> otherwise.
613  */
614 public boolean
615 isFlavorSerializedObjectType()
616 {
617   // FIXME: What is the diff between this and isMimeTypeSerializedObject?
618   return(mimeType.startsWith(javaSerializedObjectMimeType));
619 }
620
621 /*************************************************************************/
622
623 /**
624  * Tests whether or not this flavor represents a remote object.
625  *
626  * @return <code>true</code> if this flavor represents a remote object,
627  * <code>false</code> otherwise.
628  */
629 public boolean
630 isFlavorRemoteObjectType()
631 {
632   return(mimeType.startsWith(javaRemoteObjectMimeType));
633 }
634
635 /*************************************************************************/
636
637 /**
638  * Tests whether or not this flavor represents a list of files.
639  *
640  * @return <code>true</code> if this flavor represents a list of files,
641  * <code>false</code> otherwise.
642  */
643 public boolean
644 isFlavorJavaFileListType()
645 {
646   if (this.mimeType.equals(javaFileListFlavor.mimeType) &&
647       this.representationClass.equals(javaFileListFlavor.representationClass))
648     return(true);
649
650   return(false);
651 }
652
653 /*************************************************************************/
654
655 /**
656  * Returns a copy of this object.
657  *
658  * @return A copy of this object.
659  *
660  * @exception CloneNotSupportedException If the object's class does not support
661  * the Cloneable interface. Subclasses that override the clone method can also
662  * throw this exception to indicate that an instance cannot be cloned.
663  */
664 public Object clone () throws CloneNotSupportedException
665 {
666   try
667     {
668       return(super.clone());
669     }
670   catch(Exception e)
671     {
672       return(null);
673     }
674 }
675
676 /*************************************************************************/
677
678 /**
679  * This method test the specified <code>DataFlavor</code> for equality
680  * against this object.  This will be true if the MIME type and
681  * representation type are the equal.
682  *
683  * @param flavor The <code>DataFlavor</code> to test against.
684  *
685  * @return <code>true</code> if the flavor is equal to this object,
686  * <code>false</code> otherwise.
687  */
688 public boolean
689 equals(DataFlavor flavor)
690 {
691   if (flavor == null)
692     return(false);
693
694   if (!this.mimeType.toLowerCase().equals(flavor.mimeType.toLowerCase()))
695     return(false);
696
697   if (!this.representationClass.equals(flavor.representationClass))
698     return(false);
699
700   return(true);
701 }
702
703 /*************************************************************************/
704
705 /**
706  * This method test the specified <code>Object</code> for equality
707  * against this object.  This will be true if the following conditions
708  * are met:
709  * <p>
710  * <ul>
711  * <li>The object is not <code>null</code>.</li>
712  * <li>The object is an instance of <code>DataFlavor</code>.</li>
713  * <li>The object's MIME type and representation class are equal to
714  * this object's.</li>
715  * </ul>
716  *
717  * @param obj The <code>Object</code> to test against.
718  *
719  * @return <code>true</code> if the flavor is equal to this object,
720  * <code>false</code> otherwise.
721  */
722 public boolean
723 equals(Object obj)
724 {
725   if (!(obj instanceof DataFlavor))
726     return(false);
727
728   return(equals((DataFlavor)obj));
729 }
730
731 /*************************************************************************/
732
733 /**
734  * Tests whether or not the specified string is equal to the MIME type
735  * of this object.
736  *
737  * @param str The string to test against.
738  *
739  * @return <code>true</code> if the string is equal to this object's MIME
740  * type, <code>false</code> otherwise.
741  *
742  * @deprecated Not compatible with <code>hashCode()</code>.
743  *             Use <code>isMimeTypeEqual()</code>
744  */
745 public boolean
746 equals(String str)
747 {
748   return(isMimeTypeEqual(str));
749 }
750
751 /*************************************************************************/
752
753 /**
754  * Returns the hash code for this data flavor.
755  * The hash code is based on the (lower case) mime type and the
756  * representation class.
757  */
758 public int
759 hashCode()
760 {
761   return(mimeType.toLowerCase().hashCode()^representationClass.hashCode());
762 }
763
764 /*************************************************************************/
765
766 /**
767  * Returns <code>true</code> when the given <code>DataFlavor</code>
768  * matches this one.
769  */
770 public boolean
771 match(DataFlavor dataFlavor)
772 {
773   // XXX - How is this different from equals?
774   return(equals(dataFlavor));
775 }
776
777 /*************************************************************************/
778
779 /**
780  * This method exists for backward compatibility.  It simply returns
781  * the same name/value pair passed in.
782  *
783  * @param name The parameter name.
784  * @param value The parameter value.
785  *
786  * @return The name/value pair.
787  *
788  * @deprecated
789  */
790 protected String
791 normalizeMimeTypeParameter(String name, String value)
792 {
793   return(name + "=" + value);
794 }
795
796 /*************************************************************************/
797
798 /**
799  * This method exists for backward compatibility.  It simply returns
800  * the MIME type string unchanged.
801  *
802  * @param type The MIME type.
803  * 
804  * @return The MIME type.
805  *
806  * @deprecated
807  */
808 protected String
809 normalizeMimeType(String type)
810 {
811   return(type);
812 }
813
814 /*************************************************************************/
815
816 /**
817  * Serialize this class.
818  *
819  * @param stream The <code>ObjectOutput</code> stream to serialize to.
820  *
821  * @exception IOException If an error occurs.
822  */
823 public void
824 writeExternal(ObjectOutput stream) throws IOException
825 {
826   // FIXME: Implement me
827 }
828
829 /*************************************************************************/
830
831 /**
832  * De-serialize this class.
833  *
834  * @param stream The <code>ObjectInput</code> stream to deserialize from.
835  *
836  * @exception IOException If an error ocurs.
837  * @exception ClassNotFoundException If the class for an object being restored
838  * cannot be found.
839  */
840 public void
841 readExternal(ObjectInput stream) throws IOException, ClassNotFoundException
842 {
843   // FIXME: Implement me
844 }
845
846 /*************************************************************************/
847
848 /**
849  * Returns a string representation of this DataFlavor. Including the
850  * representation class name, MIME type and human presentable name.
851  */
852 public String
853 toString()
854 {
855   return("DataFlavor[representationClass="
856          + representationClass.getName()
857          + ",mimeType="
858          + mimeType
859          + "humanPresentableName="
860          + humanPresentableName);
861 }
862
863 /*************************************************************************/
864
865 /**
866  * XXX - Currently returns <code>plainTextFlavor</code>.
867  */
868 public static final DataFlavor
869 getTextPlainUnicodeFlavor()
870 {
871   return(plainTextFlavor);
872 }
873
874 /*************************************************************************/
875
876 /**
877  * XXX - Currently returns <code>java.io.InputStream</code>.
878  *
879  * @since 1.3
880  */
881 public final Class
882 getDefaultRepresentationClass()
883 {
884   return(java.io.InputStream.class);
885 }
886 /*************************************************************************/
887
888 /**
889  * XXX - Currently returns <code>java.io.InputStream</code>.
890  */
891 public final String
892 getDefaultRepresentationClassAsString()
893 {
894   return(getDefaultRepresentationClass().getName());
895 }
896
897 /*************************************************************************/
898
899 /**
900  * Selects the best supported text flavor on this implementation.
901  * Returns <code>null</code> when none of the given flavors is liked.
902  *
903  * The <code>DataFlavor</code> returned the first data flavor in the
904  * array that has either a representation class which is (a subclass of)
905  * <code>Reader</code> or <code>String</code>, or has a representation
906  * class which is (a subclass of) <code>InputStream</code> and has a
907  * primary MIME type of "text" and has an supported encoding.
908  */
909 public static final DataFlavor
910 selectBestTextFlavor(DataFlavor[] availableFlavors)
911 {
912   for(int i=0; i<availableFlavors.length; i++)
913     {
914       DataFlavor df = availableFlavors[i];
915       Class c = df.representationClass;
916
917       // A Reader or String is good.
918       if ((Reader.class.isAssignableFrom(c))
919           || (String.class.isAssignableFrom(c)))
920         {
921           return df;
922         }
923
924       // A InputStream is good if the mime primary type is "text"
925       if ((InputStream.class.isAssignableFrom(c))
926           && ("text".equals(df.getPrimaryType())))
927         {
928           String encoding = availableFlavors[i].getParameter("charset");
929           if (encoding == null)
930             encoding = "us-ascii";
931           Reader r = null;
932           try
933             {
934               // Try to construct a dummy reader with the found encoding
935               r = new InputStreamReader
936                     (new ByteArrayInputStream(new byte[0]), encoding);
937             }
938           catch(UnsupportedEncodingException uee) { /* ignore */ }
939           if (r != null)
940             return df;
941         }
942     }
943
944   // Nothing found
945   return(null);
946 }
947
948 /*************************************************************************/
949
950 /**
951  * Creates a <code>Reader</code> for a given <code>Transferable</code>.
952  *
953  * If the representation class is a (subclass of) <code>Reader</code>
954  * then an instance of the representation class is returned. If the
955  * representatation class is a <code>String</code> then a
956  * <code>StringReader</code> is returned. And if the representation class
957  * is a (subclass of) <code>InputStream</code> and the primary MIME type
958  * is "text" then a <code>InputStreamReader</code> for the correct charset
959  * encoding is returned.
960  *
961  * @param transferable The <code>Transferable</code> for which a text
962  *                     <code>Reader</code> is requested.
963  *
964  * @exception IllegalArgumentException If the representation class is not one
965  * of the seven listed above or the Transferable has null data.
966  * @exception NullPointerException If the Transferable is null.
967  * @exception UnsupportedFlavorException when the transferable doesn't
968  * support this <code>DataFlavor</code>. Or if the representable class
969  * isn't a (subclass of) <code>Reader</code>, <code>String</code>,
970  * <code>InputStream</code> and/or the primary MIME type isn't "text".
971  * @exception IOException when any IOException occurs.
972  * @exception UnsupportedEncodingException if the "charset" isn't supported
973  * on this platform.
974  */
975 public Reader getReaderForText(Transferable transferable)
976   throws UnsupportedFlavorException, IOException
977 {
978     if (!transferable.isDataFlavorSupported(this))
979         throw new UnsupportedFlavorException(this);
980
981     if (Reader.class.isAssignableFrom(representationClass))
982         return((Reader)transferable.getTransferData(this));
983
984     if (String.class.isAssignableFrom(representationClass))
985         return(new StringReader((String)transferable.getTransferData(this)));
986
987     if (InputStream.class.isAssignableFrom(representationClass)
988         && "text".equals(getPrimaryType()))
989       {
990         InputStream in = (InputStream)transferable.getTransferData(this);
991         String encoding = getParameter("charset");
992         if (encoding == null)
993             encoding = "us-ascii";
994         return(new InputStreamReader(in, encoding));
995       }
996
997     throw new UnsupportedFlavorException(this);
998 }
999
1000   /**
1001    * Returns whether the representation class for this DataFlavor is
1002    * @see java.nio.ByteBuffer or a subclass thereof.
1003    *
1004    * @since 1.4
1005    */
1006   public boolean isRepresentationClassByteBuffer ()
1007   {
1008     return ByteBuffer.class.isAssignableFrom (representationClass);
1009   }
1010
1011   /**
1012    * Returns whether the representation class for this DataFlavor is
1013    * @see java.nio.CharBuffer or a subclass thereof.
1014    *
1015    * @since 1.4
1016    */
1017   public boolean isRepresentationClassCharBuffer ()
1018   {
1019     return CharBuffer.class.isAssignableFrom (representationClass);
1020   }
1021
1022   /**
1023    * Returns whether the representation class for this DataFlavor is
1024    * @see java.io.Reader or a subclass thereof.
1025    *
1026    * @since 1.4
1027    */
1028   public boolean isRepresentationClassReader ()
1029   {
1030     return Reader.class.isAssignableFrom (representationClass);
1031   }
1032
1033 } // class DataFlavor
1034