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