jdk/src/solaris/classes/sun/awt/X11/XDataTransferer.java
changeset 2 90ce3da70b43
child 4363 212067ed03e4
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 2003-2005 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package sun.awt.X11;
       
    27 
       
    28 import java.awt.Image;
       
    29 
       
    30 import java.awt.datatransfer.DataFlavor;
       
    31 
       
    32 import java.awt.image.BufferedImage;
       
    33 import java.awt.image.ColorModel;
       
    34 import java.awt.image.WritableRaster;
       
    35 
       
    36 import java.io.InputStream;
       
    37 import java.io.IOException;
       
    38 
       
    39 import java.util.ArrayList;
       
    40 import java.util.Iterator;
       
    41 import java.util.List;
       
    42 
       
    43 import javax.imageio.ImageIO;
       
    44 import javax.imageio.ImageTypeSpecifier;
       
    45 import javax.imageio.ImageWriter;
       
    46 import javax.imageio.spi.ImageWriterSpi;
       
    47 
       
    48 import sun.awt.datatransfer.DataTransferer;
       
    49 import sun.awt.datatransfer.ToolkitThreadBlockedHandler;
       
    50 
       
    51 /**
       
    52  * Platform-specific support for the data transfer subsystem.
       
    53  */
       
    54 public class XDataTransferer extends DataTransferer {
       
    55     static final XAtom FILE_NAME_ATOM = XAtom.get("FILE_NAME");
       
    56     static final XAtom DT_NET_FILE_ATOM = XAtom.get("_DT_NETFILE");
       
    57     static final XAtom PNG_ATOM = XAtom.get("PNG");
       
    58     static final XAtom JFIF_ATOM = XAtom.get("JFIF");
       
    59     static final XAtom TARGETS_ATOM = XAtom.get("TARGETS");
       
    60     static final XAtom INCR_ATOM = XAtom.get("INCR");
       
    61     static final XAtom MULTIPLE_ATOM = XAtom.get("MULTIPLE");
       
    62 
       
    63     /**
       
    64      * Singleton constructor
       
    65      */
       
    66     private XDataTransferer() {
       
    67     }
       
    68 
       
    69     private static XDataTransferer transferer;
       
    70 
       
    71     static XDataTransferer getInstanceImpl() {
       
    72         synchronized (XDataTransferer.class) {
       
    73             if (transferer == null) {
       
    74                 transferer = new XDataTransferer();
       
    75             }
       
    76         }
       
    77         return transferer;
       
    78     }
       
    79 
       
    80     public String getDefaultUnicodeEncoding() {
       
    81         return "iso-10646-ucs-2";
       
    82     }
       
    83 
       
    84     public boolean isLocaleDependentTextFormat(long format) {
       
    85         return false;
       
    86     }
       
    87 
       
    88     public boolean isTextFormat(long format) {
       
    89         return super.isTextFormat(format)
       
    90             || isMimeFormat(format, "text");
       
    91     }
       
    92 
       
    93     protected String getCharsetForTextFormat(Long lFormat) {
       
    94         long format = lFormat.longValue();
       
    95         if (isMimeFormat(format, "text")) {
       
    96             String nat = getNativeForFormat(format);
       
    97             DataFlavor df = new DataFlavor(nat, null);
       
    98             // Ignore the charset parameter of the MIME type if the subtype
       
    99             // doesn't support charset.
       
   100             if (!DataTransferer.doesSubtypeSupportCharset(df)) {
       
   101                 return null;
       
   102             }
       
   103             String charset = df.getParameter("charset");
       
   104             if (charset != null) {
       
   105                 return charset;
       
   106             }
       
   107         }
       
   108         return super.getCharsetForTextFormat(lFormat);
       
   109     }
       
   110 
       
   111     public boolean isFileFormat(long format) {
       
   112         return format == FILE_NAME_ATOM.getAtom() ||
       
   113             format == DT_NET_FILE_ATOM.getAtom();
       
   114     }
       
   115 
       
   116     public boolean isImageFormat(long format) {
       
   117         return format == PNG_ATOM.getAtom() ||
       
   118             format == JFIF_ATOM.getAtom() ||
       
   119             isMimeFormat(format, "image");
       
   120     }
       
   121 
       
   122     protected Long getFormatForNativeAsLong(String str) {
       
   123         // Just get the atom. If it has already been retrived
       
   124         // once, we'll get a copy so this should be very fast.
       
   125         long atom = XAtom.get(str).getAtom();
       
   126         return Long.valueOf(atom);
       
   127     }
       
   128 
       
   129     protected String getNativeForFormat(long format) {
       
   130         return getTargetNameForAtom(format);
       
   131     }
       
   132 
       
   133     public ToolkitThreadBlockedHandler getToolkitThreadBlockedHandler() {
       
   134         return XToolkitThreadBlockedHandler.getToolkitThreadBlockedHandler();
       
   135     }
       
   136 
       
   137     /**
       
   138      * Gets an format name for a given format (atom)
       
   139      */
       
   140     private String getTargetNameForAtom(long atom) {
       
   141         return XAtom.get(atom).getName();
       
   142     }
       
   143 
       
   144     protected byte[] imageToPlatformBytes(Image image, long format)
       
   145       throws IOException {
       
   146         String mimeType = null;
       
   147         if (format == PNG_ATOM.getAtom()) {
       
   148             mimeType = "image/png";
       
   149         } else if (format == JFIF_ATOM.getAtom()) {
       
   150             mimeType = "image/jpeg";
       
   151         } else {
       
   152             // Check if an image MIME format.
       
   153             try {
       
   154                 String nat = getNativeForFormat(format);
       
   155                 DataFlavor df = new DataFlavor(nat);
       
   156                 String primaryType = df.getPrimaryType();
       
   157                 if ("image".equals(primaryType)) {
       
   158                     mimeType = df.getPrimaryType() + "/" + df.getSubType();
       
   159                 }
       
   160             } catch (Exception e) {
       
   161                 // Not an image MIME format.
       
   162             }
       
   163         }
       
   164         if (mimeType != null) {
       
   165             return imageToStandardBytes(image, mimeType);
       
   166         } else {
       
   167             String nativeFormat = getNativeForFormat(format);
       
   168             throw new IOException("Translation to " + nativeFormat +
       
   169                                   " is not supported.");
       
   170         }
       
   171     }
       
   172 
       
   173     /**
       
   174      * Translates either a byte array or an input stream which contain
       
   175      * platform-specific image data in the given format into an Image.
       
   176      */
       
   177     protected Image platformImageBytesOrStreamToImage(InputStream inputStream,
       
   178                                                       byte[] bytes,
       
   179                                                       long format)
       
   180       throws IOException {
       
   181         String mimeType = null;
       
   182         if (format == PNG_ATOM.getAtom()) {
       
   183             mimeType = "image/png";
       
   184         } else if (format == JFIF_ATOM.getAtom()) {
       
   185             mimeType = "image/jpeg";
       
   186         } else {
       
   187             // Check if an image MIME format.
       
   188             try {
       
   189                 String nat = getNativeForFormat(format);
       
   190                 DataFlavor df = new DataFlavor(nat);
       
   191                 String primaryType = df.getPrimaryType();
       
   192                 if ("image".equals(primaryType)) {
       
   193                     mimeType = df.getPrimaryType() + "/" + df.getSubType();
       
   194                 }
       
   195             } catch (Exception e) {
       
   196                 // Not an image MIME format.
       
   197             }
       
   198         }
       
   199         if (mimeType != null) {
       
   200             return standardImageBytesOrStreamToImage(inputStream, bytes, mimeType);
       
   201         } else {
       
   202             String nativeFormat = getNativeForFormat(format);
       
   203             throw new IOException("Translation from " + nativeFormat +
       
   204                                   " is not supported.");
       
   205         }
       
   206     }
       
   207 
       
   208     protected String[] dragQueryFile(byte[] bytes) {
       
   209         XToolkit.awtLock();
       
   210         try {
       
   211             return XlibWrapper.XTextPropertyToStringList(bytes,
       
   212                                                          XAtom.get("STRING").getAtom());
       
   213         } finally {
       
   214             XToolkit.awtUnlock();
       
   215         }
       
   216     }
       
   217 
       
   218     /**
       
   219      * Returns true if and only if the name of the specified format Atom
       
   220      * constitutes a valid MIME type with the specified primary type.
       
   221      */
       
   222     private boolean isMimeFormat(long format, String primaryType) {
       
   223         String nat = getNativeForFormat(format);
       
   224 
       
   225         if (nat == null) {
       
   226             return false;
       
   227         }
       
   228 
       
   229         try {
       
   230             DataFlavor df = new DataFlavor(nat);
       
   231             if (primaryType.equals(df.getPrimaryType())) {
       
   232                 return true;
       
   233             }
       
   234         } catch (Exception e) {
       
   235             // Not a MIME format.
       
   236         }
       
   237 
       
   238         return false;
       
   239     }
       
   240 
       
   241     /*
       
   242      * The XDnD protocol prescribes that the Atoms used as targets for data
       
   243      * transfer should have string names that represent the corresponding MIME
       
   244      * types.
       
   245      * To meet this requirement we check if the passed native format constitutes
       
   246      * a valid MIME and return a list of flavors to which the data in this MIME
       
   247      * type can be translated by the Data Transfer subsystem.
       
   248      */
       
   249     public List getPlatformMappingsForNative(String nat) {
       
   250         List flavors = new ArrayList();
       
   251 
       
   252         if (nat == null) {
       
   253             return flavors;
       
   254         }
       
   255 
       
   256         DataFlavor df = null;
       
   257 
       
   258         try {
       
   259             df = new DataFlavor(nat);
       
   260         } catch (Exception e) {
       
   261             // The string doesn't constitute a valid MIME type.
       
   262             return flavors;
       
   263         }
       
   264 
       
   265         Object value = df;
       
   266         final String primaryType = df.getPrimaryType();
       
   267         final String baseType = primaryType + "/" + df.getSubType();
       
   268 
       
   269         // For text formats we map natives to MIME strings instead of data
       
   270         // flavors to enable dynamic text native-to-flavor mapping generation.
       
   271         // See SystemFlavorMap.getFlavorsForNative() for details.
       
   272         if ("text".equals(primaryType)) {
       
   273             value = primaryType + "/" + df.getSubType();
       
   274         } else if ("image".equals(primaryType)) {
       
   275             Iterator readers = ImageIO.getImageReadersByMIMEType(baseType);
       
   276             if (readers.hasNext()) {
       
   277                 flavors.add(DataFlavor.imageFlavor);
       
   278             }
       
   279         }
       
   280 
       
   281         flavors.add(value);
       
   282 
       
   283         return flavors;
       
   284     }
       
   285 
       
   286     private static ImageTypeSpecifier defaultSpecifier = null;
       
   287 
       
   288     private ImageTypeSpecifier getDefaultImageTypeSpecifier() {
       
   289         if (defaultSpecifier == null) {
       
   290             ColorModel model = ColorModel.getRGBdefault();
       
   291             WritableRaster raster =
       
   292                 model.createCompatibleWritableRaster(10, 10);
       
   293 
       
   294             BufferedImage bufferedImage =
       
   295                 new BufferedImage(model, raster, model.isAlphaPremultiplied(),
       
   296                                   null);
       
   297 
       
   298             defaultSpecifier = new ImageTypeSpecifier(bufferedImage);
       
   299         }
       
   300 
       
   301         return defaultSpecifier;
       
   302     }
       
   303 
       
   304     /*
       
   305      * The XDnD protocol prescribes that the Atoms used as targets for data
       
   306      * transfer should have string names that represent the corresponding MIME
       
   307      * types.
       
   308      * To meet this requirement we return a list of formats that represent
       
   309      * MIME types to which the data in this flavor can be translated by the Data
       
   310      * Transfer subsystem.
       
   311      */
       
   312     public List getPlatformMappingsForFlavor(DataFlavor df) {
       
   313         List natives = new ArrayList(1);
       
   314 
       
   315         if (df == null) {
       
   316             return natives;
       
   317         }
       
   318 
       
   319         String charset = df.getParameter("charset");
       
   320         String baseType = df.getPrimaryType() + "/" + df.getSubType();
       
   321         String mimeType = baseType;
       
   322 
       
   323         if (charset != null && DataTransferer.isFlavorCharsetTextType(df)) {
       
   324             mimeType += ";charset=" + charset;
       
   325         }
       
   326 
       
   327         // Add a mapping to the MIME native whenever the representation class
       
   328         // doesn't require translation.
       
   329         if (df.getRepresentationClass() != null &&
       
   330             (df.isRepresentationClassInputStream() ||
       
   331              df.isRepresentationClassByteBuffer() ||
       
   332              byteArrayClass.equals(df.getRepresentationClass()))) {
       
   333             natives.add(mimeType);
       
   334         }
       
   335 
       
   336         if (DataFlavor.imageFlavor.equals(df)) {
       
   337             String[] mimeTypes = ImageIO.getWriterMIMETypes();
       
   338             if (mimeTypes != null) {
       
   339                 for (int i = 0; i < mimeTypes.length; i++) {
       
   340                     Iterator writers =
       
   341                         ImageIO.getImageWritersByMIMEType(mimeTypes[i]);
       
   342 
       
   343                     while (writers.hasNext()) {
       
   344                         ImageWriter imageWriter = (ImageWriter)writers.next();
       
   345                         ImageWriterSpi writerSpi =
       
   346                             imageWriter.getOriginatingProvider();
       
   347 
       
   348                         if (writerSpi != null &&
       
   349                             writerSpi.canEncodeImage(getDefaultImageTypeSpecifier())) {
       
   350                             natives.add(mimeTypes[i]);
       
   351                             break;
       
   352                         }
       
   353                     }
       
   354                 }
       
   355             }
       
   356         } else if (DataTransferer.isFlavorCharsetTextType(df)) {
       
   357             final Iterator iter = DataTransferer.standardEncodings();
       
   358 
       
   359             // stringFlavor is semantically equivalent to the standard
       
   360             // "text/plain" MIME type.
       
   361             if (DataFlavor.stringFlavor.equals(df)) {
       
   362                 baseType = "text/plain";
       
   363             }
       
   364 
       
   365             while (iter.hasNext()) {
       
   366                 String encoding = (String)iter.next();
       
   367                 if (!encoding.equals(charset)) {
       
   368                     natives.add(baseType + ";charset=" + encoding);
       
   369                 }
       
   370             }
       
   371 
       
   372             // Add a MIME format without specified charset.
       
   373             if (!natives.contains(baseType)) {
       
   374                 natives.add(baseType);
       
   375             }
       
   376         }
       
   377 
       
   378         return natives;
       
   379     }
       
   380 }