1 /* 2 * Copyright (c) 2000, 2005, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.awt.datatransfer; 27 28 import java.awt.datatransfer.DataFlavor; 29 import java.awt.datatransfer.Transferable; 30 import java.awt.datatransfer.UnsupportedFlavorException; 31 32 import java.io.IOException; 33 34 import java.util.HashMap; 35 import java.util.Iterator; 36 import 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 */ 57 public 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 }