001: /*
002: * Copyright 2000-2004 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.awt.motif;
027:
028: import java.awt.Image;
029:
030: import java.awt.datatransfer.DataFlavor;
031:
032: import java.awt.image.BufferedImage;
033: import java.awt.image.ColorModel;
034: import java.awt.image.WritableRaster;
035:
036: import java.io.InputStream;
037: import java.io.IOException;
038:
039: import java.util.ArrayList;
040: import java.util.Iterator;
041: import java.util.List;
042:
043: import javax.imageio.ImageIO;
044: import javax.imageio.ImageTypeSpecifier;
045: import javax.imageio.ImageWriter;
046: import javax.imageio.spi.ImageWriterSpi;
047:
048: import sun.awt.datatransfer.DataTransferer;
049: import sun.awt.datatransfer.ToolkitThreadBlockedHandler;
050:
051: /**
052: * Platform-specific support for the data transfer subsystem.
053: *
054: * @author Roger Brinkley
055: * @author Danila Sinopalnikov
056: * @version 1.30, 05/05/07
057: *
058: * @since 1.3.1
059: */
060: public class MDataTransferer extends DataTransferer {
061: private static final long FILE_NAME_ATOM;
062: private static final long DT_NET_FILE_ATOM;
063: private static final long PNG_ATOM;
064: private static final long JFIF_ATOM;
065:
066: static {
067: FILE_NAME_ATOM = getAtomForTarget("FILE_NAME");
068: DT_NET_FILE_ATOM = getAtomForTarget("_DT_NETFILE");
069: PNG_ATOM = getAtomForTarget("PNG");
070: JFIF_ATOM = getAtomForTarget("JFIF");
071: }
072:
073: /**
074: * Singleton constructor
075: */
076: private MDataTransferer() {
077: }
078:
079: private static MDataTransferer transferer;
080:
081: static MDataTransferer getInstanceImpl() {
082: if (transferer == null) {
083: synchronized (MDataTransferer.class) {
084: if (transferer == null) {
085: transferer = new MDataTransferer();
086: }
087: }
088: }
089: return transferer;
090: }
091:
092: public String getDefaultUnicodeEncoding() {
093: return "iso-10646-ucs-2";
094: }
095:
096: public boolean isLocaleDependentTextFormat(long format) {
097: return false;
098: }
099:
100: public boolean isTextFormat(long format) {
101: return super .isTextFormat(format)
102: || isMimeFormat(format, "text");
103: }
104:
105: protected String getCharsetForTextFormat(Long lFormat) {
106: long format = lFormat.longValue();
107: if (isMimeFormat(format, "text")) {
108: String nat = getNativeForFormat(format);
109: DataFlavor df = new DataFlavor(nat, null);
110: // Ignore the charset parameter of the MIME type if the subtype
111: // doesn't support charset.
112: if (!DataTransferer.doesSubtypeSupportCharset(df)) {
113: return null;
114: }
115: String charset = df.getParameter("charset");
116: if (charset != null) {
117: return charset;
118: }
119: }
120: return super .getCharsetForTextFormat(lFormat);
121: }
122:
123: public boolean isFileFormat(long format) {
124: return format == FILE_NAME_ATOM || format == DT_NET_FILE_ATOM;
125: }
126:
127: public boolean isImageFormat(long format) {
128: return format == PNG_ATOM || format == JFIF_ATOM
129: || isMimeFormat(format, "image");
130: }
131:
132: protected Long getFormatForNativeAsLong(String str) {
133: // Just get the atom. If it has already been retrived
134: // once, we'll get a copy so this should be very fast.
135: long atom = getAtomForTarget(str);
136: if (atom <= 0) {
137: throw new InternalError("Cannot register a target");
138: }
139: return Long.valueOf(atom);
140: }
141:
142: protected String getNativeForFormat(long format) {
143: return getTargetNameForAtom(format);
144: }
145:
146: public ToolkitThreadBlockedHandler getToolkitThreadBlockedHandler() {
147: return MToolkitThreadBlockedHandler
148: .getToolkitThreadBlockedHandler();
149: }
150:
151: /**
152: * Gets an atom for a format name.
153: */
154: static native long getAtomForTarget(String name);
155:
156: /**
157: * Gets an format name for a given format (atom)
158: */
159: private static native String getTargetNameForAtom(long atom);
160:
161: protected byte[] imageToPlatformBytes(Image image, long format)
162: throws IOException {
163: String mimeType = null;
164: if (format == PNG_ATOM) {
165: mimeType = "image/png";
166: } else if (format == JFIF_ATOM) {
167: mimeType = "image/jpeg";
168: } else {
169: // Check if an image MIME format.
170: try {
171: String nat = getNativeForFormat(format);
172: DataFlavor df = new DataFlavor(nat);
173: String primaryType = df.getPrimaryType();
174: if ("image".equals(primaryType)) {
175: mimeType = df.getPrimaryType() + "/"
176: + df.getSubType();
177: }
178: } catch (Exception e) {
179: // Not an image MIME format.
180: }
181: }
182: if (mimeType != null) {
183: return imageToStandardBytes(image, mimeType);
184: } else {
185: String nativeFormat = getNativeForFormat(format);
186: throw new IOException("Translation to " + nativeFormat
187: + " is not supported.");
188: }
189: }
190:
191: /**
192: * Translates either a byte array or an input stream which contain
193: * platform-specific image data in the given format into an Image.
194: */
195: protected Image platformImageBytesOrStreamToImage(
196: InputStream inputStream, byte[] bytes, long format)
197: throws IOException {
198: String mimeType = null;
199: if (format == PNG_ATOM) {
200: mimeType = "image/png";
201: } else if (format == JFIF_ATOM) {
202: mimeType = "image/jpeg";
203: } else {
204: // Check if an image MIME format.
205: try {
206: String nat = getNativeForFormat(format);
207: DataFlavor df = new DataFlavor(nat);
208: String primaryType = df.getPrimaryType();
209: if ("image".equals(primaryType)) {
210: mimeType = df.getPrimaryType() + "/"
211: + df.getSubType();
212: }
213: } catch (Exception e) {
214: // Not an image MIME format.
215: }
216: }
217: if (mimeType != null) {
218: return standardImageBytesOrStreamToImage(inputStream,
219: bytes, mimeType);
220: } else {
221: String nativeFormat = getNativeForFormat(format);
222: throw new IOException("Translation from " + nativeFormat
223: + " is not supported.");
224: }
225: }
226:
227: /**
228: * Returns true if and only if the name of the specified format Atom
229: * constitutes a valid MIME type with the specified primary type.
230: */
231: private boolean isMimeFormat(long format, String primaryType) {
232: String nat = getNativeForFormat(format);
233:
234: if (nat == null) {
235: return false;
236: }
237:
238: try {
239: DataFlavor df = new DataFlavor(nat);
240: if (primaryType.equals(df.getPrimaryType())) {
241: return true;
242: }
243: } catch (Exception e) {
244: // Not a MIME format.
245: }
246:
247: return false;
248: }
249:
250: /*
251: * The XDnD protocol prescribes that the Atoms used as targets for data
252: * transfer should have string names that represent the corresponding MIME
253: * types.
254: * To meet this requirement we check if the passed native format constitutes
255: * a valid MIME and return a list of flavors to which the data in this MIME
256: * type can be translated by the Data Transfer subsystem.
257: */
258: public List getPlatformMappingsForNative(String nat) {
259: List flavors = new ArrayList();
260:
261: if (nat == null) {
262: return flavors;
263: }
264:
265: DataFlavor df = null;
266:
267: try {
268: df = new DataFlavor(nat);
269: } catch (Exception e) {
270: // The string doesn't constitute a valid MIME type.
271: return flavors;
272: }
273:
274: Object value = df;
275: final String primaryType = df.getPrimaryType();
276: final String baseType = primaryType + "/" + df.getSubType();
277:
278: // For text formats we map natives to MIME strings instead of data
279: // flavors to enable dynamic text native-to-flavor mapping generation.
280: // See SystemFlavorMap.getFlavorsForNative() for details.
281: if ("text".equals(primaryType)) {
282: value = primaryType + "/" + df.getSubType();
283: } else if ("image".equals(primaryType)) {
284: Iterator readers = ImageIO
285: .getImageReadersByMIMEType(baseType);
286: if (readers.hasNext()) {
287: flavors.add(DataFlavor.imageFlavor);
288: }
289: }
290:
291: flavors.add(value);
292:
293: return flavors;
294: }
295:
296: private static ImageTypeSpecifier defaultSpecifier = null;
297:
298: private ImageTypeSpecifier getDefaultImageTypeSpecifier() {
299: if (defaultSpecifier == null) {
300: ColorModel model = ColorModel.getRGBdefault();
301: WritableRaster raster = model
302: .createCompatibleWritableRaster(10, 10);
303:
304: BufferedImage bufferedImage = new BufferedImage(model,
305: raster, model.isAlphaPremultiplied(), null);
306:
307: defaultSpecifier = new ImageTypeSpecifier(bufferedImage);
308: }
309:
310: return defaultSpecifier;
311: }
312:
313: /*
314: * The XDnD protocol prescribes that the Atoms used as targets for data
315: * transfer should have string names that represent the corresponding MIME
316: * types.
317: * To meet this requirement we return a list of formats that represent
318: * MIME types to which the data in this flavor can be translated by the Data
319: * Transfer subsystem.
320: */
321: public List getPlatformMappingsForFlavor(DataFlavor df) {
322: List natives = new ArrayList(1);
323:
324: if (df == null) {
325: return natives;
326: }
327:
328: String charset = df.getParameter("charset");
329: String baseType = df.getPrimaryType() + "/" + df.getSubType();
330: String mimeType = baseType;
331:
332: if (charset != null
333: && DataTransferer.isFlavorCharsetTextType(df)) {
334: mimeType += ";charset=" + charset;
335: }
336:
337: // Add a mapping to the MIME native whenever the representation class
338: // doesn't require translation.
339: if (df.getRepresentationClass() != null
340: && (df.isRepresentationClassInputStream()
341: || df.isRepresentationClassByteBuffer() || byteArrayClass
342: .equals(df.getRepresentationClass()))) {
343: natives.add(mimeType);
344: }
345:
346: if (DataFlavor.imageFlavor.equals(df)) {
347: String[] mimeTypes = ImageIO.getWriterMIMETypes();
348: if (mimeTypes != null) {
349: for (int i = 0; i < mimeTypes.length; i++) {
350: Iterator writers = ImageIO
351: .getImageWritersByMIMEType(mimeTypes[i]);
352:
353: while (writers.hasNext()) {
354: ImageWriter imageWriter = (ImageWriter) writers
355: .next();
356: ImageWriterSpi writerSpi = imageWriter
357: .getOriginatingProvider();
358:
359: if (writerSpi != null
360: && writerSpi
361: .canEncodeImage(getDefaultImageTypeSpecifier())) {
362: natives.add(mimeTypes[i]);
363: break;
364: }
365: }
366: }
367: }
368: } else if (DataTransferer.isFlavorCharsetTextType(df)) {
369: final Iterator iter = DataTransferer.standardEncodings();
370:
371: // stringFlavor is semantically equivalent to the standard
372: // "text/plain" MIME type.
373: if (DataFlavor.stringFlavor.equals(df)) {
374: baseType = "text/plain";
375: }
376:
377: while (iter.hasNext()) {
378: String encoding = (String) iter.next();
379: if (!encoding.equals(charset)) {
380: natives.add(baseType + ";charset=" + encoding);
381: }
382: }
383:
384: // Add a MIME format without specified charset.
385: if (!natives.contains(baseType)) {
386: natives.add(baseType);
387: }
388: }
389:
390: return natives;
391: }
392:
393: protected native String[] dragQueryFile(byte[] bytes);
394: }
|