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