1 /* 2 * Copyright (c) 2000, 2015, 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 javafx.scene.input; 27 28 import java.io.File; 29 import java.security.AccessControlContext; 30 import java.security.AccessController; 31 import java.security.Permission; 32 import java.util.List; 33 import java.util.Map; 34 import java.util.Set; 35 36 import javafx.scene.image.Image; 37 import javafx.util.Pair; 38 39 import com.sun.javafx.tk.PermissionHelper; 40 import com.sun.javafx.tk.TKClipboard; 41 import com.sun.javafx.tk.Toolkit; 42 43 /** 44 * Represents an operating system clipboard, on which data may be placed during, for 45 * example, cut, copy, and paste operations. 46 * <p> 47 * To access the general system clipboard, use the following code: 48 * <pre><code> 49 * Clipboard clipboard = Clipboard.getSystemClipboard(); 50 * </code></pre> 51 * <p> 52 * There is only ever one instance of the system clipboard in the application, so it is 53 * perfectly acceptable to stash a reference to it somewhere handy if you so choose. 54 * <p> 55 * The Clipboard operates on the concept of having a single conceptual item on the 56 * clipboard at any one time -- though it may be placed on the clipboard in different 57 * formats. For example, the user might select text in an HTML editor and press the 58 * ctrl+c or cmd+c to copy it. In this case, the same text might be available on the 59 * clipboard both as HTML and as plain text. There are two copies of the data on the 60 * clipboard, but they both represent the same data. 61 * <p> 62 * Content is specified on the Clipboard by using the {@link #setContent} 63 * method. First, construct a ClipboardContent object, then invoke setContent. Every time 64 * setContent is called, any previous data on the clipboard is cleared and replaced with 65 * this new content. 66 * <pre><code> 67 * final Clipboard clipboard = Clipboard.getSystemClipboard(); 68 * final ClipboardContent content = new ClipboardContent(); 69 * content.putString("Some text"); 70 * content.putHtml("<b>Some</b> text"); 71 * clipboard.setContent(content); 72 * </code></pre> 73 * <p> 74 * The {@link ClipboardContent} class is simply a map with convenience methods for dealing 75 * with common data types added to a clipboard. 76 * <p> 77 * Because multiple representations of the same data may exist on the clipboard, and because 78 * different applications have different capabilities for handling different content types, 79 * it is important to place as many data representations on the clipboard as is practical to 80 * facilitate external applications. Note that sometimes the operating system might be 81 * helpful in some cases and add multiple types for you. For example, the Mac might set the 82 * plain text string for you when you specify the RTF type. How and under what circumstances 83 * this occurs is outside the realm of this specification, consult your OS documentation. 84 * <p> 85 * When reading data off the clipboard, it is important to look for the richest 86 * supported type first. For example, if I have a text document which supports embedding of 87 * images and media formats, when pasting content from the clipboard I should first check to 88 * see if the content can be represented as media or as an image. If not, then I might check 89 * for RTF or HTML or whatever rich text format is supported by my document type. If not, 90 * then I might just take a String. 91 * <p> 92 * Or for example, if I have a plain text document, then I would simple get a String 93 * representation and use that, if available. I can check to see if the clipboard "hasHtml" 94 * or "hasString". 95 * <pre><code> 96 * if (clipboard.hasString()) { ... } 97 * </pre></code> 98 * <p> 99 * In addition to the common or built in types, you may put any arbitrary data onto the 100 * clipboard (assuming it is serializable). 101 * <p> 102 * Content types are defined by the DataFormat objects. 103 * The DataFormat class defines an immutable object, and there are a number of static final 104 * fields for common DataFormat types. Of course application specific DataFormat types can also be 105 * declared and used. The following two methods are equivalent (and the second call 106 * will override the first!) 107 * <pre><code> 108 * ClipboardContent content = new ClipboardContent(); 109 * content.putString("some text"); 110 * content.put(DataFormat.PLAIN_TEXT, "other text"); 111 * </pre></code> 112 * <p> 113 * On embedded platforms that do not have their own windowing system, the 114 * Clipboard returned from Clipboard.getSystemClipboard() might not be 115 * accessible from outside the JavaFX application. In this case, the clipboard 116 * returned by Clipboard.getSystemClipboard() can be used for exchange of data 117 * between different parts of one JavaFX application but cannot be used to 118 * exchange data between multiple applications. 119 * @since JavaFX 2.0 120 */ 121 public class Clipboard { 122 123 /** 124 * Whether user has put something on this clipboard. Needed for DnD. 125 */ 126 private boolean contentPut = false; 127 128 // future: 129 /* 130 * JavaFX supports the concept of multiple independently named clipboards. There is a 131 * predefined clipboard which represents the main system clipboard, but it is possible 132 * to create custom clipboards if you so desire. Some platforms, such as Mac OS X, 133 * define a number of different named clipboards. You can access these from JavaFX by 134 * simply creating a Clipboard with the correct name. Typically there is no need to do 135 * so in your applications since the UI Controls will use the correct System clipboards, 136 * if applicable. 137 * <p> 138 * 139 * Sometimes you may want to put a reference to a data representation on the clipboard 140 * 141 * rather than the data itself. For example, the user may have selected a large block of 142 * text, and wants to copy this to the clipboard. Instead of having to actually produce 143 * multiple copies of this text, a reference can be placed on the clipboard instead. When 144 * the developer subsequently attempts to read the value off the clipboard, this reference 145 * is resolved. Or suppose that I want to put a Node on the clipboard, such that the 146 * representation of that Node on the clipboard is as an image. 147 * <pre><code> 148 * final Node node = ...; 149 * ClipboardReference ref = new ClipboardReference() { 150 * @Override public InputStream get() { 151 * // convert the node to an image 152 * // return an input stream to the image 153 * ... 154 * } 155 * }; 156 * clipboard.putReference(DataFormat.IMAGE_TIFF, ref); 157 * </pre></code> 158 * <p> 159 * At the appropriate time, a client reading off the clipboard will ask for the data and 160 * the system will invoke the provided callback to stream the image data over to the client. 161 */ 162 163 private final AccessControlContext acc = AccessController.getContext(); 164 165 /** 166 * Gets the current system clipboard, through which data can be stored and 167 * retrieved. There is ever only one system clipboard for a JavaFX application. 168 * @return The single system clipboard, used for cut / copy / paste operations 169 */ 170 public static Clipboard getSystemClipboard() { 171 try { 172 final SecurityManager securityManager = System.getSecurityManager(); 173 if (securityManager != null) { 174 final Permission clipboardPerm = 175 PermissionHelper.getAccessClipboardPermission(); 176 securityManager.checkPermission(clipboardPerm); 177 } 178 return getSystemClipboardImpl(); 179 } catch (final SecurityException e) { 180 return getLocalClipboardImpl(); 181 } 182 } 183 184 TKClipboard peer; 185 186 // Only allow Dragboard to extend from this 187 Clipboard(TKClipboard peer) { 188 Toolkit.getToolkit().checkFxUserThread(); 189 if (peer == null) { 190 throw new NullPointerException(); 191 } 192 peer.setSecurityContext(acc); 193 this.peer = peer; 194 } 195 196 /** 197 * Clears the clipboard of any and all content. Any subsequent call to 198 * {@link #getContentTypes} before putting more content on the clipboard 199 * will result in an empty set being returned. 200 */ 201 public final void clear() { 202 setContent(null); 203 } 204 205 /** 206 * Gets the set of DataFormat types on this Clipboard instance which have 207 * associated data registered on the clipboard. This set will always 208 * be non-null and immutable. If the Clipboard is subsequently modifed, 209 * this returned set is not updated. 210 * 211 * @return A non-null immutable set of content types. 212 */ 213 public final Set<DataFormat> getContentTypes() { 214 return peer.getContentTypes(); 215 } 216 217 /** 218 * Puts content onto the clipboard. This call will always result in 219 * clearing all previous content from the clipboard, and replacing 220 * it with whatever content is specified in the supplied 221 * ClipboardContent map. 222 * 223 * @param content The content to put on the clipboard. If null, the 224 * clipboard is simply cleared and no new content added. 225 * @return True if successful, false if the content fails to be added. 226 * @throws NullPointerException if null data reference is passed for any 227 * format 228 */ 229 // public abstract boolean setContent(DataFormat uti, Object content); 230 public final boolean setContent(Map<DataFormat, Object> content) { 231 Toolkit.getToolkit().checkFxUserThread(); 232 if (content == null) { 233 contentPut = false; 234 peer.putContent(new Pair[0]); 235 return true; 236 } else { 237 Pair<DataFormat, Object>[] data = new Pair[content.size()]; 238 int index = 0; 239 for (Map.Entry<DataFormat, Object> entry : content.entrySet()) { 240 data[index++] = new Pair<DataFormat, Object>(entry.getKey(), entry.getValue()); 241 } 242 contentPut = peer.putContent(data); 243 return contentPut; 244 } 245 } 246 247 /** 248 * Returns the content stored in this clipboard of the given type, or null 249 * if there is no content with this type. 250 * @return The content associated with this type, or null if there is none 251 */ 252 public final Object getContent(DataFormat dataFormat) { 253 Toolkit.getToolkit().checkFxUserThread(); 254 return getContentImpl(dataFormat); 255 } 256 257 /** 258 * Getting content overridable by internal subclasses. 259 */ 260 Object getContentImpl(DataFormat dataFormat) { 261 return peer.getContent(dataFormat); 262 } 263 264 /** 265 * Tests whether there is any content on this clipboard of the given DataFormat type. 266 * @return true if there is content on this clipboard for this type 267 */ 268 public final boolean hasContent(DataFormat dataFormat) { 269 Toolkit.getToolkit().checkFxUserThread(); 270 return peer.hasContent(dataFormat); 271 } 272 273 /** 274 * Gets whether a plain text String (DataFormat.PLAIN_TEXT) has been registered 275 * on this Clipboard. 276 * @return true if <code>hasContent(DataFormat.PLAIN_TEXT)</code> returns true, false otherwise 277 */ 278 public final boolean hasString() { 279 return hasContent(DataFormat.PLAIN_TEXT); 280 } 281 282 /** 283 * Gets the plain text String from the clipboard which had previously 284 * been registered. This is equivalent to invoking 285 * <code>getContent(DataFormat.PLAIN_TEXT)</code>. If no such entry exists, 286 * null is returned. 287 * @return The String on the clipboard associated with DataFormat.PLAIN_TEXT, 288 * or null if there is not one. 289 */ 290 public final String getString() { 291 return (String) getContent(DataFormat.PLAIN_TEXT); 292 } 293 294 /** 295 * Gets whether a url String (DataFormat.URL) has been registered 296 * on this Clipboard. 297 * @return true if hasContent(DataFormat.URL) returns true, false otherwise 298 */ 299 public final boolean hasUrl() { 300 return hasContent(DataFormat.URL); 301 } 302 303 /** 304 * Gets the URL String from the clipboard which had previously 305 * been registered. This is equivalent to invoking 306 * <code>getContent(DataFormat.URL)</code>. If no such entry exists, 307 * null is returned. 308 * @return The String on the clipboard associated with DataFormat.URL, 309 * or null if there is not one. 310 */ 311 public final String getUrl() { 312 return (String) getContent(DataFormat.URL); 313 } 314 315 /** 316 * Gets whether an HTML text String (DataFormat.HTML) has been registered 317 * on this Clipboard. 318 * @return true if <code>hasContent(DataFormat.HTML)</code> returns true, false otherwise 319 */ 320 public final boolean hasHtml() { 321 return hasContent(DataFormat.HTML); 322 } 323 324 /** 325 * Gets the HTML text String from the clipboard which had previously 326 * been registered. This is equivalent to invoking 327 * <code>getContent(DataFormat.HTML)</code>. If no such entry exists, 328 * null is returned. 329 * @return The String on the clipboard associated with DataFormat.HTML, 330 * or null if there is not one. 331 */ 332 public final String getHtml() { 333 return (String) getContent(DataFormat.HTML); 334 } 335 336 /** 337 * Gets whether an RTF String (DataFormat.RTF) has been registered 338 * on this Clipboard. 339 * @return true if hasContent(DataFormat.RTF) returns true, false otherwise 340 */ 341 public final boolean hasRtf() { 342 return hasContent(DataFormat.RTF); 343 } 344 345 /** 346 * Gets the RTF text String from the clipboard which had previously 347 * been registered. This is equivalent to invoking 348 * <code>getContent(DataFormat.RTF)</code>. If no such entry exists, 349 * null is returned. 350 * @return The String on the clipboard associated with DataFormat.RTF, 351 * or null if there is not one. 352 */ 353 public final String getRtf() { 354 return (String) getContent(DataFormat.RTF); 355 } 356 357 /** 358 * Gets whether an Image (DataFormat.IMAGE) has been registered 359 * on this Clipboard. 360 * @return true if hasContent(DataFormat.IMAGE) returns true, false otherwise 361 */ 362 public final boolean hasImage() { 363 return hasContent(DataFormat.IMAGE); 364 }; 365 366 /** 367 * Gets the Image from the clipboard which had previously 368 * been registered. This is equivalent to invoking 369 * <code>getContent(DataFormat.IMAGE)</code>. If no such entry exists, 370 * null is returned. 371 * @return The Image on the clipboard associated with DataFormat.IMAGE, 372 * or null if there is not one. 373 */ 374 public final Image getImage() { 375 return (Image) getContent(DataFormat.IMAGE); 376 } 377 378 /** 379 * Gets whether an List of Files (DataFormat.FILES) has been registered 380 * on this Clipboard. 381 * @return true if hasContent(DataFormat.FILES) returns true, false otherwise 382 */ 383 public final boolean hasFiles() { 384 return hasContent(DataFormat.FILES); 385 } 386 387 /** 388 * Gets the List of Files from the clipboard which had previously 389 * been registered. This is equivalent to invoking 390 * <code>getContent(DataFormat.FILES)</code>. If no such entry exists, 391 * null is returned. 392 * @return The List of Files on the clipboard associated with DataFormat.FILES, 393 * or null if there is not one. 394 */ 395 public final List<File> getFiles() { 396 return (List<File>) getContent(DataFormat.FILES); 397 } 398 399 /** 400 * @treatAsPrivate implementation detail 401 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 402 */ 403 @Deprecated 404 public boolean impl_contentPut() { 405 return contentPut; 406 } 407 408 private static Clipboard systemClipboard; 409 410 private static synchronized Clipboard getSystemClipboardImpl() { 411 if (systemClipboard == null) { 412 systemClipboard = 413 new Clipboard(Toolkit.getToolkit().getSystemClipboard()); 414 } 415 return systemClipboard; 416 } 417 418 private static Clipboard localClipboard; 419 420 private static synchronized Clipboard getLocalClipboardImpl() { 421 if (localClipboard == null) { 422 localClipboard = 423 new Clipboard(Toolkit.getToolkit().createLocalClipboard()); 424 } 425 return localClipboard; 426 } 427 }