1 /* 2 * Copyright (c) 2000, 2014, 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.setToSortedDataFlavorArray(flavorsToData.keySet()); 101 } 102 } finally { 103 clipboard.closeClipboard(); 104 } 105 } 106 107 private boolean fetchOneFlavor(SunClipboard clipboard, DataFlavor flavor, 108 Long lFormat, HashMap cached_data) 109 { 110 if (!flavorsToData.containsKey(flavor)) { 111 long format = lFormat.longValue(); 112 Object data = null; 113 114 if (!cached_data.containsKey(lFormat)) { 115 try { 116 data = clipboard.getClipboardData(format); 117 } catch (IOException e) { 118 data = e; 119 } catch (Throwable e) { 120 e.printStackTrace(); 121 } 122 123 // Cache this data, even if it's null, so we don't have to go 124 // to native code again for this format. 125 cached_data.put(lFormat, data); 126 } else { 127 data = cached_data.get(lFormat); 128 } 129 130 // Casting IOException to byte array causes ClassCastException. 131 // We should handle IOException separately - do not wrap them into 132 // DataFactory and report failure. 133 if (data instanceof IOException) { 134 flavorsToData.put(flavor, data); 135 return false; 136 } else if (data != null) { 137 flavorsToData.put(flavor, new DataFactory(format, 138 (byte[])data)); 139 return true; 140 } 141 } 142 143 return false; 144 } 145 146 public DataFlavor[] getTransferDataFlavors() { 147 return flavors.clone(); 148 } 149 150 public boolean isDataFlavorSupported(DataFlavor flavor) { 151 return flavorsToData.containsKey(flavor); 152 } 153 154 public Object getTransferData(DataFlavor flavor) 155 throws UnsupportedFlavorException, IOException 156 { 157 if (!isDataFlavorSupported(flavor)) { 158 throw new UnsupportedFlavorException(flavor); 159 } 160 Object ret = flavorsToData.get(flavor); 161 if (ret instanceof IOException) { 162 // rethrow IOExceptions generated while fetching data 163 throw (IOException)ret; 164 } else if (ret instanceof DataFactory) { 165 // Now we can render the data 166 DataFactory factory = (DataFactory)ret; 167 ret = factory.getTransferData(flavor); 168 } 169 return ret; 170 } 171 172 }