blob: 6526a25e4a955b0773497eec135f99aa5b659eeb [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-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
26package sun.awt.datatransfer;
27
28import java.awt.datatransfer.DataFlavor;
29import java.awt.datatransfer.Transferable;
30import java.awt.datatransfer.UnsupportedFlavorException;
31
32import java.io.IOException;
33
34import java.util.HashMap;
35import java.util.Iterator;
36import java.util.Map;
37
38
39/**
40 * Reads all of the data from the system Clipboard which the data transfer
41 * subsystem knows how to translate. This includes all text data, File Lists,
42 * Serializable objects, Remote objects, and properly registered, arbitrary
43 * data as InputStreams. The data is stored in byte format until requested
44 * by client code. At that point, the data is converted, if necessary, into
45 * the proper format to deliver to the application.
46 *
47 * This hybrid pre-fetch/delayed-rendering approach allows us to circumvent
48 * the API restriction that client code cannot lock the Clipboard to discover
49 * its formats before requesting data in a particular format, while avoiding
50 * the overhead of fully rendering all data ahead of time.
51 *
52 * @author David Mendenhall
53 * @author Danila Sinopalnikov
54 *
55 * @since 1.4 (appeared in modified form as FullyRenderedTransferable in 1.3.1)
56 */
57public class ClipboardTransferable implements Transferable {
58 private final HashMap flavorsToData = new HashMap();
59 private DataFlavor[] flavors = new DataFlavor[0];
60
61 private final class DataFactory {
62 final long format;
63 final byte[] data;
64 DataFactory(long format, byte[] data) {
65 this.format = format;
66 this.data = data;
67 }
68
69 public Object getTransferData(DataFlavor flavor) throws IOException {
70 return DataTransferer.getInstance().
71 translateBytes(data, flavor, format,
72 ClipboardTransferable.this);
73 }
74 }
75
76 public ClipboardTransferable(SunClipboard clipboard) {
77
78 clipboard.openClipboard(null);
79
80 try {
81 long[] formats = clipboard.getClipboardFormats();
82
83 if (formats != null && formats.length > 0) {
84 // Since the SystemFlavorMap will specify many DataFlavors
85 // which map to the same format, we should cache data as we
86 // read it.
87 HashMap cached_data = new HashMap(formats.length, 1.0f);
88
89 Map flavorsForFormats = DataTransferer.getInstance().
90 getFlavorsForFormats(formats, SunClipboard.flavorMap);
91 for (Iterator iter = flavorsForFormats.keySet().iterator();
92 iter.hasNext(); )
93 {
94 DataFlavor flavor = (DataFlavor)iter.next();
95 Long lFormat = (Long)flavorsForFormats.get(flavor);
96
97 fetchOneFlavor(clipboard, flavor, lFormat, cached_data);
98 }
99
100 flavors = DataTransferer.getInstance().
101 setToSortedDataFlavorArray(flavorsToData.keySet(),
102 flavorsForFormats);
103 }
104 } finally {
105 clipboard.closeClipboard();
106 }
107 }
108
109 private boolean fetchOneFlavor(SunClipboard clipboard, DataFlavor flavor,
110 Long lFormat, HashMap cached_data)
111 {
112 if (!flavorsToData.containsKey(flavor)) {
113 long format = lFormat.longValue();
114 Object data = null;
115
116 if (!cached_data.containsKey(lFormat)) {
117 try {
118 data = clipboard.getClipboardData(format);
119 } catch (IOException e) {
120 data = e;
121 } catch (Throwable e) {
122 e.printStackTrace();
123 }
124
125 // Cache this data, even if it's null, so we don't have to go
126 // to native code again for this format.
127 cached_data.put(lFormat, data);
128 } else {
129 data = cached_data.get(lFormat);
130 }
131
132 // Casting IOException to byte array causes ClassCastException.
133 // We should handle IOException separately - do not wrap them into
134 // DataFactory and report failure.
135 if (data instanceof IOException) {
136 flavorsToData.put(flavor, data);
137 return false;
138 } else if (data != null) {
139 flavorsToData.put(flavor, new DataFactory(format,
140 (byte[])data));
141 return true;
142 }
143 }
144
145 return false;
146 }
147
148 public DataFlavor[] getTransferDataFlavors() {
149 return (DataFlavor[])flavors.clone();
150 }
151
152 public boolean isDataFlavorSupported(DataFlavor flavor) {
153 return flavorsToData.containsKey(flavor);
154 }
155
156 public Object getTransferData(DataFlavor flavor)
157 throws UnsupportedFlavorException, IOException
158 {
159 if (!isDataFlavorSupported(flavor)) {
160 throw new UnsupportedFlavorException(flavor);
161 }
162 Object ret = flavorsToData.get(flavor);
163 if (ret instanceof IOException) {
164 // rethrow IOExceptions generated while fetching data
165 throw (IOException)ret;
166 } else if (ret instanceof DataFactory) {
167 // Now we can render the data
168 DataFactory factory = (DataFactory)ret;
169 ret = factory.getTransferData(flavor);
170 }
171 return ret;
172 }
173
174}