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