comparison dwt/dnd/Clipboard.d @ 0:380af2bdd8e5

Upload of whole dwt tree
author Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com>
date Sat, 09 Aug 2008 17:00:02 +0200
parents
children 1a8b3cb347e0
comparison
equal deleted inserted replaced
-1:000000000000 0:380af2bdd8e5
1 /*******************************************************************************
2 * Copyright (c) 2000, 2007 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 module dwt.dnd;
12
13
14 import dwt.*;
15 import dwt.widgets.*;
16 import dwt.internal.cocoa.OS;
17
18 /**
19 * The <code>Clipboard</code> provides a mechanism for transferring data from one
20 * application to another or within an application.
21 *
22 * <p>IMPORTANT: This class is <em>not</em> intended to be subclassed.</p>
23 */
24 public class Clipboard {
25
26 Display display;
27 int scrap = 0;
28
29 /**
30 * Constructs a new instance of this class. Creating an instance of a Clipboard
31 * may cause system resources to be allocated depending on the platform. It is therefore
32 * mandatory that the Clipboard instance be disposed when no longer required.
33 *
34 * @param display the display on which to allocate the clipboard
35 *
36 * @exception DWTException <ul>
37 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
38 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
39 * </ul>
40 *
41 * @see Clipboard#dispose
42 * @see Clipboard#checkSubclass
43 */
44 public Clipboard(Display display) {
45 checkSubclass ();
46 if (display is null) {
47 display = Display.getCurrent();
48 if (display is null) {
49 display = Display.getDefault();
50 }
51 }
52 if (display.getThread() !is Thread.currentThread()) {
53 DND.error(DWT.ERROR_THREAD_INVALID_ACCESS);
54 }
55 this.display = display;
56 }
57
58 /**
59 * Checks that this class can be subclassed.
60 * <p>
61 * The DWT class library is intended to be subclassed
62 * only at specific, controlled points. This method enforces this
63 * rule unless it is overridden.
64 * </p><p>
65 * <em>IMPORTANT:</em> By providing an implementation of this
66 * method that allows a subclass of a class which does not
67 * normally allow subclassing to be created, the implementer
68 * agrees to be fully responsible for the fact that any such
69 * subclass will likely fail between DWT releases and will be
70 * strongly platform specific. No support is provided for
71 * user-written classes which are implemented in this fashion.
72 * </p><p>
73 * The ability to subclass outside of the allowed DWT classes
74 * is intended purely to enable those not on the DWT development
75 * team to implement patches in order to get around specific
76 * limitations in advance of when those limitations can be
77 * addressed by the team. Subclassing should not be attempted
78 * without an intimate and detailed understanding of the hierarchy.
79 * </p>
80 *
81 * @exception DWTException <ul>
82 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
83 * </ul>
84 */
85 protected void checkSubclass () {
86 String name = getClass().getName ();
87 String validName = Clipboard.class.getName();
88 if (!validName.opEquals(name)) {
89 DND.error (DWT.ERROR_INVALID_SUBCLASS);
90 }
91 }
92 /**
93 * Throws an <code>DWTException</code> if the receiver can not
94 * be accessed by the caller. This may include both checks on
95 * the state of the receiver and more generally on the entire
96 * execution context. This method <em>should</em> be called by
97 * widget implementors to enforce the standard DWT invariants.
98 * <p>
99 * Currently, it is an error to invoke any method (other than
100 * <code>isDisposed()</code>) on a widget that has had its
101 * <code>dispose()</code> method called. It is also an error
102 * to call widget methods from any thread that is different
103 * from the thread that created the widget.
104 * </p><p>
105 * In future releases of DWT, there may be more or fewer error
106 * checks and exceptions may be thrown for different reasons.
107 * </p>
108 *
109 * @exception DWTException <ul>
110 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
111 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
112 * </ul>
113 */
114 protected void checkWidget () {
115 Display display = this.display;
116 if (display is null) DND.error (DWT.ERROR_WIDGET_DISPOSED);
117 if (display.getThread() !is Thread.currentThread ()) DND.error (DWT.ERROR_THREAD_INVALID_ACCESS);
118 if (display.isDisposed()) DND.error(DWT.ERROR_WIDGET_DISPOSED);
119 }
120
121 /**
122 * If this clipboard is currently the owner of the data on the system clipboard,
123 * clear the contents. If this clipboard is not the owner, then nothing is done.
124 * Note that there are clipboard assistant applications that take ownership of
125 * data or make copies of data when it is placed on the clipboard. In these
126 * cases, it may not be possible to clear the clipboard.
127 *
128 * @exception DWTException <ul>
129 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
130 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
131 * </ul>
132 *
133 * @since 3.1
134 */
135 public void clearContents() {
136 clearContents(DND.CLIPBOARD);
137 }
138
139 /**
140 * If this clipboard is currently the owner of the data on the specified
141 * clipboard, clear the contents. If this clipboard is not the owner, then
142 * nothing is done.
143 *
144 * <p>Note that there are clipboard assistant applications that take ownership
145 * of data or make copies of data when it is placed on the clipboard. In these
146 * cases, it may not be possible to clear the clipboard.</p>
147 *
148 * <p>The clipboards value is either one of the clipboard constants defined in
149 * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
150 * (that is, using the <code>int</code> "|" operator) two or more
151 * of those <code>DND</code> clipboard constants.</p>
152 *
153 * @param clipboards to be cleared
154 *
155 * @exception DWTException <ul>
156 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
157 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
158 * </ul>
159 *
160 * @see DND#CLIPBOARD
161 * @see DND#SELECTION_CLIPBOARD
162 *
163 * @since 3.1
164 */
165 public void clearContents(int clipboards) {
166 checkWidget();
167 if ((clipboards & DND.CLIPBOARD) is 0 || scrap is 0) return;
168 int oldScrap = scrap;
169 scrap = 0;
170 int[] currentScrap = new int[1];
171 if (OS.GetCurrentScrap(currentScrap) !is OS.noErr) return;
172 if (currentScrap[0] is oldScrap) {
173 OS.ClearCurrentScrap();
174 }
175 }
176
177 /**
178 * Disposes of the operating system resources associated with the clipboard.
179 * The data will still be available on the system clipboard after the dispose
180 * method is called.
181 *
182 * <p>NOTE: On some platforms the data will not be available once the application
183 * has exited or the display has been disposed.</p>
184 *
185 * @exception DWTException <ul>
186 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
187 * </ul>
188 */
189 public void dispose () {
190 if (isDisposed()) return;
191 if (display.getThread() !is Thread.currentThread()) DND.error(DWT.ERROR_THREAD_INVALID_ACCESS);
192 display = null;
193 }
194
195 /**
196 * Retrieve the data of the specified type currently available on the system
197 * clipboard. Refer to the specific subclass of <code>Transfer</code> to
198 * determine the type of object returned.
199 *
200 * <p>The following snippet shows text and RTF text being retrieved from the
201 * clipboard:</p>
202 *
203 * <code><pre>
204 * Clipboard clipboard = new Clipboard(display);
205 * TextTransfer textTransfer = TextTransfer.getInstance();
206 * String textData = (String)clipboard.getContents(textTransfer);
207 * if (textData !is null) System.out.println("Text is "+textData);
208 * RTFTransfer rtfTransfer = RTFTransfer.getInstance();
209 * String rtfData = (String)clipboard.getContents(rtfTransfer);
210 * if (rtfData !is null) System.out.println("RTF Text is "+rtfData);
211 * clipboard.dispose();
212 * </code></pre>
213 *
214 * @param transfer the transfer agent for the type of data being requested
215 * @return the data obtained from the clipboard or null if no data of this type is available
216 *
217 * @exception DWTException <ul>
218 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
219 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
220 * </ul>
221 * @exception IllegalArgumentException <ul>
222 * <li>ERROR_NULL_ARGUMENT - if transfer is null</li>
223 * </ul>
224 *
225 * @see Transfer
226 */
227 public Object getContents(Transfer transfer) {
228 return getContents(transfer, DND.CLIPBOARD);
229 }
230
231 /**
232 * Retrieve the data of the specified type currently available on the specified
233 * clipboard. Refer to the specific subclass of <code>Transfer</code> to
234 * determine the type of object returned.
235 *
236 * <p>The following snippet shows text and RTF text being retrieved from the
237 * clipboard:</p>
238 *
239 * <code><pre>
240 * Clipboard clipboard = new Clipboard(display);
241 * TextTransfer textTransfer = TextTransfer.getInstance();
242 * String textData = (String)clipboard.getContents(textTransfer);
243 * if (textData !is null) System.out.println("Text is "+textData);
244 * RTFTransfer rtfTransfer = RTFTransfer.getInstance();
245 * String rtfData = (String)clipboard.getContents(rtfTransfer, DND.CLIPBOARD);
246 * if (rtfData !is null) System.out.println("RTF Text is "+rtfData);
247 * clipboard.dispose();
248 * </code></pre>
249 *
250 * <p>The clipboards value is either one of the clipboard constants defined in
251 * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
252 * (that is, using the <code>int</code> "|" operator) two or more
253 * of those <code>DND</code> clipboard constants.</p>
254 *
255 * @param transfer the transfer agent for the type of data being requested
256 * @param clipboards on which to look for data
257 *
258 * @return the data obtained from the clipboard or null if no data of this type is available
259 *
260 * @exception DWTException <ul>
261 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
262 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
263 * </ul>
264 * @exception IllegalArgumentException <ul>
265 * <li>ERROR_NULL_ARGUMENT - if transfer is null</li>
266 * </ul>
267 *
268 * @see Transfer
269 * @see DND#CLIPBOARD
270 * @see DND#SELECTION_CLIPBOARD
271 *
272 * @since 3.1
273 */
274 public Object getContents(Transfer transfer, int clipboards) {
275 checkWidget();
276 if (transfer is null) DND.error(DWT.ERROR_NULL_ARGUMENT);
277 if ((clipboards & DND.CLIPBOARD) is 0) return null;
278 int[] scrap = new int[1];
279 if (OS.GetCurrentScrap(scrap) !is OS.noErr) return null;
280 int[] typeIds = transfer.getTypeIds();
281 int[] size = new int[1];
282 // get data from system clipboard
283 for (int i=0; i<typeIds.length; i++) {
284 int type = typeIds[i];
285 size[0] = 0;
286 if (OS.GetScrapFlavorSize(scrap[0], type, size) is OS.noErr && size[0] > 0) {
287 byte[] buffer = new byte[size[0]];
288 if (OS.GetScrapFlavorData(scrap[0], type, size, buffer) is OS.noErr) {
289 TransferData tdata = new TransferData();
290 tdata.type = type;
291 tdata.data = new byte[1][];
292 tdata.data[0] = buffer;
293 return transfer.nativeToJava(tdata);
294 }
295 }
296 }
297 return null; // No data available for this transfer
298 }
299
300 /**
301 * Returns <code>true</code> if the clipboard has been disposed,
302 * and <code>false</code> otherwise.
303 * <p>
304 * This method gets the dispose state for the clipboard.
305 * When a clipboard has been disposed, it is an error to
306 * invoke any other method using the clipboard.
307 * </p>
308 *
309 * @return <code>true</code> when the widget is disposed and <code>false</code> otherwise
310 *
311 * @since 3.0
312 */
313 public bool isDisposed () {
314 return (display is null);
315 }
316
317 /**
318 * Place data of the specified type on the system clipboard. More than one type
319 * of data can be placed on the system clipboard at the same time. Setting the
320 * data clears any previous data from the system clipboard, regardless of type.
321 *
322 * <p>NOTE: On some platforms, the data is immediately copied to the system
323 * clipboard but on other platforms it is provided upon request. As a result,
324 * if the application modifies the data object it has set on the clipboard, that
325 * modification may or may not be available when the data is subsequently
326 * requested.</p>
327 *
328 * <p>The following snippet shows text and RTF text being set on the copy/paste
329 * clipboard:
330 * </p>
331 *
332 * <code><pre>
333 * Clipboard clipboard = new Clipboard(display);
334 * String textData = "Hello World";
335 * String rtfData = "{\\rtf1\\b\\i Hello World}";
336 * TextTransfer textTransfer = TextTransfer.getInstance();
337 * RTFTransfer rtfTransfer = RTFTransfer.getInstance();
338 * Transfer[] transfers = new Transfer[]{textTransfer, rtfTransfer};
339 * Object[] data = new Object[]{textData, rtfData};
340 * clipboard.setContents(data, transfers);
341 * clipboard.dispose();
342 * </code></pre>
343 *
344 * @param data the data to be set in the clipboard
345 * @param dataTypes the transfer agents that will convert the data to its
346 * platform specific format; each entry in the data array must have a
347 * corresponding dataType
348 *
349 * @exception IllegalArgumentException <ul>
350 * <li>ERROR_INVALID_ARGUMENT - if data is null or datatypes is null
351 * or the length of data is not the same as the length of dataTypes</li>
352 * </ul>
353 * @exception DWTException <ul>
354 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
355 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
356 * </ul>
357 * @exception DWTError <ul>
358 * <li>ERROR_CANNOT_SET_CLIPBOARD - if the clipboard is locked or otherwise unavailable</li>
359 * </ul>
360 *
361 * <p>NOTE: ERROR_CANNOT_SET_CLIPBOARD should be an DWTException, since it is a
362 * recoverable error, but can not be changed due to backward compatibility.</p>
363 */
364 public void setContents(Object[] data, Transfer[] dataTypes) {
365 setContents(data, dataTypes, DND.CLIPBOARD);
366 }
367
368 /**
369 * Place data of the specified type on the specified clipboard. More than one
370 * type of data can be placed on the specified clipboard at the same time.
371 * Setting the data clears any previous data from the specified
372 * clipboard, regardless of type.
373 *
374 * <p>NOTE: On some platforms, the data is immediately copied to the specified
375 * clipboard but on other platforms it is provided upon request. As a result,
376 * if the application modifies the data object it has set on the clipboard, that
377 * modification may or may not be available when the data is subsequently
378 * requested.</p>
379 *
380 * <p>The clipboards value is either one of the clipboard constants defined in
381 * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
382 * (that is, using the <code>int</code> "|" operator) two or more
383 * of those <code>DND</code> clipboard constants.</p>
384 *
385 * <p>The following snippet shows text and RTF text being set on the copy/paste
386 * clipboard:
387 * </p>
388 *
389 * <code><pre>
390 * Clipboard clipboard = new Clipboard(display);
391 * String textData = "Hello World";
392 * String rtfData = "{\\rtf1\\b\\i Hello World}";
393 * TextTransfer textTransfer = TextTransfer.getInstance();
394 * RTFTransfer rtfTransfer = RTFTransfer.getInstance();
395 * Transfer[] transfers = new Transfer[]{textTransfer, rtfTransfer};
396 * Object[] data = new Object[]{textData, rtfData};
397 * clipboard.setContents(data, transfers, DND.CLIPBOARD);
398 * clipboard.dispose();
399 * </code></pre>
400 *
401 * @param data the data to be set in the clipboard
402 * @param dataTypes the transfer agents that will convert the data to its
403 * platform specific format; each entry in the data array must have a
404 * corresponding dataType
405 * @param clipboards on which to set the data
406 *
407 * @exception IllegalArgumentException <ul>
408 * <li>ERROR_INVALID_ARGUMENT - if data is null or datatypes is null
409 * or the length of data is not the same as the length of dataTypes</li>
410 * </ul>
411 * @exception DWTException <ul>
412 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
413 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
414 * </ul>
415 * @exception DWTError <ul>
416 * <li>ERROR_CANNOT_SET_CLIPBOARD - if the clipboard is locked or otherwise unavailable</li>
417 * </ul>
418 *
419 * <p>NOTE: ERROR_CANNOT_SET_CLIPBOARD should be an DWTException, since it is a
420 * recoverable error, but can not be changed due to backward compatibility.</p>
421 *
422 * @see DND#CLIPBOARD
423 * @see DND#SELECTION_CLIPBOARD
424 *
425 * @since 3.1
426 */
427 public void setContents(Object[] data, Transfer[] dataTypes, int clipboards) {
428 checkWidget();
429 if (data is null || dataTypes is null || data.length !is dataTypes.length || data.length is 0) {
430 DND.error(DWT.ERROR_INVALID_ARGUMENT);
431 }
432 for (int i = 0; i < data.length; i++) {
433 if (data[i] is null || dataTypes[i] is null || !dataTypes[i].validate(data[i])) {
434 DND.error(DWT.ERROR_INVALID_ARGUMENT);
435 }
436 }
437 if ((clipboards & DND.CLIPBOARD) is 0) return;
438 if (OS.ClearCurrentScrap() !is OS.noErr) {
439 DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD);
440 }
441 scrap = 0;
442 int[] currentScrap = new int[1];
443 if (OS.GetCurrentScrap(currentScrap) !is OS.noErr) {
444 DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD);
445 }
446 scrap = currentScrap[0];
447 // copy data directly over to System clipboard (not deferred)
448 for (int i=0; i<dataTypes.length; i++) {
449 int[] typeIds = dataTypes[i].getTypeIds();
450 for (int j=0; j<typeIds.length; j++) {
451 TransferData transferData = new TransferData();
452 transferData.type = typeIds[j];
453 dataTypes[i].javaToNative(data[i], transferData);
454 if (transferData.result !is OS.noErr) {
455 DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD);
456 }
457 //Drag and Drop can handle multiple items in one transfer but the
458 //Clipboard can not.
459 byte[] datum = transferData.data[0];
460 if (OS.PutScrapFlavor(scrap, transferData.type, 0, datum.length, datum) !is OS.noErr){
461 DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD);
462 }
463 }
464 }
465 }
466
467 /**
468 * Returns an array of the data types currently available on the system
469 * clipboard. Use with Transfer.isSupportedType.
470 *
471 * @return array of data types currently available on the system clipboard
472 *
473 * @exception DWTException <ul>
474 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
475 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
476 * </ul>
477 *
478 * @see Transfer#isSupportedType
479 *
480 * @since 3.0
481 */
482 public TransferData[] getAvailableTypes() {
483 return getAvailableTypes(DND.CLIPBOARD);
484 }
485
486 /**
487 * Returns an array of the data types currently available on the specified
488 * clipboard. Use with Transfer.isSupportedType.
489 *
490 * <p>The clipboards value is either one of the clipboard constants defined in
491 * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
492 * (that is, using the <code>int</code> "|" operator) two or more
493 * of those <code>DND</code> clipboard constants.</p>
494 *
495 * @param clipboards from which to get the data types
496 * @return array of data types currently available on the specified clipboard
497 *
498 * @exception DWTException <ul>
499 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
500 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
501 * </ul>
502 *
503 * @see Transfer#isSupportedType
504 * @see DND#CLIPBOARD
505 * @see DND#SELECTION_CLIPBOARD
506 *
507 * @since 3.1
508 */
509 public TransferData[] getAvailableTypes(int clipboards) {
510 checkWidget();
511 if ((clipboards & DND.CLIPBOARD) is 0) return new TransferData[0];
512 int[] types = _getAvailableTypes();
513 TransferData[] result = new TransferData[types.length];
514 for (int i = 0; i < types.length; i++) {
515 result[i] = new TransferData();
516 result[i].type = types[i];
517 }
518 return result;
519 }
520
521 /**
522 * Returns a platform specific list of the data types currently available on the
523 * system clipboard.
524 *
525 * <p>Note: <code>getAvailableTypeNames</code> is a utility for writing a Transfer
526 * sub-class. It should NOT be used within an application because it provides
527 * platform specific information.</p>
528 *
529 * @return a platform specific list of the data types currently available on the
530 * system clipboard
531 *
532 * @exception DWTException <ul>
533 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
534 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
535 * </ul>
536 */
537 public String[] getAvailableTypeNames() {
538 checkWidget();
539 int[] types = _getAvailableTypes();
540 String[] names = new String[types.length];
541 for (int i = 0; i < types.length; i++) {
542 int type = types[i];
543 StringBuffer sb = new StringBuffer();
544 sb.append((char)((type & 0xff000000) >> 24));
545 sb.append((char)((type & 0x00ff0000) >> 16));
546 sb.append((char)((type & 0x0000ff00) >> 8));
547 sb.append((char)((type & 0x000000ff) >> 0));
548 names[i] = sb.toString();
549 }
550 return names;
551 }
552
553 int[] _getAvailableTypes() {
554 int[] types = new int[0];
555 int[] scrap = new int[1];
556 if (OS.GetCurrentScrap(scrap) !is OS.noErr) return types;
557 int[] count = new int[1];
558 if (OS.GetScrapFlavorCount(scrap[0], count) !is OS.noErr || count[0] is 0) return types;
559 int[] info = new int[count[0] * 2];
560 if (OS.GetScrapFlavorInfoList(scrap[0], count, info) !is OS.noErr) return types;
561 types = new int[count[0]];
562 for (int i= 0; i < count [0]; i++) {
563 types[i] = info[i*2];
564 }
565 return types;
566 }
567 }