Source for java.awt.datatransfer.DataFlavor

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