Mercurial > projects > dwt2
comparison org.eclipse.swt.win32.win32.x86/src/org/eclipse/swt/dnd/Clipboard.d @ 0:6dd524f61e62
add dwt win and basic java stuff
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Mon, 02 Mar 2009 14:44:16 +0100 |
parents | |
children | 52184e4b815c |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:6dd524f61e62 |
---|---|
1 /******************************************************************************* | |
2 * Copyright (c) 2000, 2008 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 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module org.eclipse.swt.dnd.Clipboard; | |
14 | |
15 | |
16 import org.eclipse.swt.SWT; | |
17 import org.eclipse.swt.SWTError; | |
18 import org.eclipse.swt.SWTException; | |
19 import org.eclipse.swt.internal.ole.win32.COM; | |
20 import org.eclipse.swt.internal.ole.win32.OBJIDL; | |
21 import org.eclipse.swt.internal.ole.win32.extras; | |
22 import org.eclipse.swt.internal.win32.OS; | |
23 import org.eclipse.swt.widgets.Display; | |
24 | |
25 import org.eclipse.swt.dnd.Transfer; | |
26 import org.eclipse.swt.dnd.TransferData; | |
27 import org.eclipse.swt.dnd.OleEnumFORMATETC; | |
28 import org.eclipse.swt.dnd.DND; | |
29 | |
30 import java.lang.all; | |
31 import tango.core.Thread; | |
32 | |
33 /** | |
34 * The <code>Clipboard</code> provides a mechanism for transferring data from one | |
35 * application to another or within an application. | |
36 * | |
37 * <p>IMPORTANT: This class is <em>not</em> intended to be subclassed.</p> | |
38 * | |
39 * @see <a href="http://www.eclipse.org/swt/snippets/#clipboard">Clipboard snippets</a> | |
40 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ClipboardExample</a> | |
41 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> | |
42 */ | |
43 public class Clipboard { | |
44 | |
45 private Display display; | |
46 | |
47 // ole interfaces | |
48 private _IDataObjectImpl iDataObject; | |
49 private int refCount; | |
50 private Transfer[] transferAgents; | |
51 private Object[] data; | |
52 private int CFSTR_PREFERREDDROPEFFECT; | |
53 | |
54 /** | |
55 * Constructs a new instance of this class. Creating an instance of a Clipboard | |
56 * may cause system resources to be allocated depending on the platform. It is therefore | |
57 * mandatory that the Clipboard instance be disposed when no longer required. | |
58 * | |
59 * @param display the display on which to allocate the clipboard | |
60 * | |
61 * @exception SWTException <ul> | |
62 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> | |
63 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> | |
64 * </ul> | |
65 * | |
66 * @see Clipboard#dispose | |
67 * @see Clipboard#checkSubclass | |
68 */ | |
69 public this(Display display) { | |
70 checkSubclass (); | |
71 if (display is null) { | |
72 display = Display.getCurrent(); | |
73 if (display is null) { | |
74 display = Display.getDefault(); | |
75 } | |
76 } | |
77 if (display.getThread() !is Thread.getThis()) { | |
78 DND.error(SWT.ERROR_THREAD_INVALID_ACCESS); | |
79 } | |
80 this.display = display; | |
81 TCHAR* chFormatName = StrToTCHARz(0, "Preferred DropEffect"); //$NON-NLS-1$ | |
82 CFSTR_PREFERREDDROPEFFECT = OS.RegisterClipboardFormat(chFormatName); | |
83 createCOMInterfaces(); | |
84 this.AddRef(); | |
85 } | |
86 | |
87 /** | |
88 * Checks that this class can be subclassed. | |
89 * <p> | |
90 * The SWT class library is intended to be subclassed | |
91 * only at specific, controlled points. This method enforces this | |
92 * rule unless it is overridden. | |
93 * </p><p> | |
94 * <em>IMPORTANT:</em> By providing an implementation of this | |
95 * method that allows a subclass of a class which does not | |
96 * normally allow subclassing to be created, the implementer | |
97 * agrees to be fully responsible for the fact that any such | |
98 * subclass will likely fail between SWT releases and will be | |
99 * strongly platform specific. No support is provided for | |
100 * user-written classes which are implemented in this fashion. | |
101 * </p><p> | |
102 * The ability to subclass outside of the allowed SWT classes | |
103 * is intended purely to enable those not on the SWT development | |
104 * team to implement patches in order to get around specific | |
105 * limitations in advance of when those limitations can be | |
106 * addressed by the team. Subclassing should not be attempted | |
107 * without an intimate and detailed understanding of the hierarchy. | |
108 * </p> | |
109 * | |
110 * @exception SWTException <ul> | |
111 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> | |
112 * </ul> | |
113 */ | |
114 protected void checkSubclass () { | |
115 String name = this.classinfo.name; | |
116 String validName = Clipboard.classinfo.name; | |
117 if (validName!=/*eq*/name) { | |
118 DND.error (SWT.ERROR_INVALID_SUBCLASS); | |
119 } | |
120 } | |
121 | |
122 /** | |
123 * Throws an <code>SWTException</code> if the receiver can not | |
124 * be accessed by the caller. This may include both checks on | |
125 * the state of the receiver and more generally on the entire | |
126 * execution context. This method <em>should</em> be called by | |
127 * widget implementors to enforce the standard SWT invariants. | |
128 * <p> | |
129 * Currently, it is an error to invoke any method (other than | |
130 * <code>isDisposed()</code>) on a widget that has had its | |
131 * <code>dispose()</code> method called. It is also an error | |
132 * to call widget methods from any thread that is different | |
133 * from the thread that created the widget. | |
134 * </p><p> | |
135 * In future releases of SWT, there may be more or fewer error | |
136 * checks and exceptions may be thrown for different reasons. | |
137 * </p> | |
138 * | |
139 * @exception SWTException <ul> | |
140 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
141 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
142 * </ul> | |
143 */ | |
144 protected void checkWidget () { | |
145 Display display = this.display; | |
146 if (display is null) DND.error (SWT.ERROR_WIDGET_DISPOSED); | |
147 if (display.getThread() !is Thread.getThis ()) DND.error (SWT.ERROR_THREAD_INVALID_ACCESS); | |
148 if (display.isDisposed()) DND.error(SWT.ERROR_WIDGET_DISPOSED); | |
149 } | |
150 | |
151 /** | |
152 * If this clipboard is currently the owner of the data on the system clipboard, | |
153 * clear the contents. If this clipboard is not the owner, then nothing is done. | |
154 * Note that there are clipboard assistant applications that take ownership of | |
155 * data or make copies of data when it is placed on the clipboard. In these | |
156 * cases, it may not be possible to clear the clipboard. | |
157 * | |
158 * @exception SWTException <ul> | |
159 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
160 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
161 * </ul> | |
162 * | |
163 * @since 3.1 | |
164 */ | |
165 public void clearContents() { | |
166 clearContents(DND.CLIPBOARD); | |
167 } | |
168 | |
169 /** | |
170 * If this clipboard is currently the owner of the data on the specified | |
171 * clipboard, clear the contents. If this clipboard is not the owner, then | |
172 * nothing is done. | |
173 * | |
174 * <p>Note that there are clipboard assistant applications that take ownership | |
175 * of data or make copies of data when it is placed on the clipboard. In these | |
176 * cases, it may not be possible to clear the clipboard.</p> | |
177 * | |
178 * <p>The clipboards value is either one of the clipboard constants defined in | |
179 * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together | |
180 * (that is, using the <code>int</code> "|" operator) two or more | |
181 * of those <code>DND</code> clipboard constants.</p> | |
182 * | |
183 * @param clipboards to be cleared | |
184 * | |
185 * @exception SWTException <ul> | |
186 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
187 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
188 * </ul> | |
189 * | |
190 * @see DND#CLIPBOARD | |
191 * @see DND#SELECTION_CLIPBOARD | |
192 * | |
193 * @since 3.1 | |
194 */ | |
195 public void clearContents(int clipboards) { | |
196 checkWidget(); | |
197 if ((clipboards & DND.CLIPBOARD) !is 0) { | |
198 /* OleIsCurrentClipboard([in] pDataObject) | |
199 * The argument pDataObject is owned by the caller so reference count does not | |
200 * need to be incremented. | |
201 */ | |
202 if (COM.OleIsCurrentClipboard(this.iDataObject) is COM.S_OK) { | |
203 /* OleSetClipboard([in] pDataObject) | |
204 * The argument pDataObject is owned by the caller so reference count does not | |
205 * need to be incremented. | |
206 */ | |
207 COM.OleSetClipboard(null); | |
208 } | |
209 } | |
210 } | |
211 | |
212 /** | |
213 * Disposes of the operating system resources associated with the clipboard. | |
214 * The data will still be available on the system clipboard after the dispose | |
215 * method is called. | |
216 * | |
217 * <p>NOTE: On some platforms the data will not be available once the application | |
218 * has exited or the display has been disposed.</p> | |
219 * | |
220 * @exception SWTException <ul> | |
221 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> | |
222 * </ul> | |
223 */ | |
224 public void dispose () { | |
225 if (isDisposed()) return; | |
226 if (display.getThread() !is Thread.getThis ()) DND.error(SWT.ERROR_THREAD_INVALID_ACCESS); | |
227 /* OleIsCurrentClipboard([in] pDataObject) | |
228 * The argument pDataObject is owned by the caller so reference count does not | |
229 * need to be incremented. | |
230 */ | |
231 if (COM.OleIsCurrentClipboard(this.iDataObject) is COM.S_OK) { | |
232 COM.OleFlushClipboard(); | |
233 } | |
234 this.Release(); | |
235 display = null; | |
236 } | |
237 | |
238 /** | |
239 * Retrieve the data of the specified type currently available on the system | |
240 * clipboard. Refer to the specific subclass of <code>Transfer</code> to | |
241 * determine the type of object returned. | |
242 * | |
243 * <p>The following snippet shows text and RTF text being retrieved from the | |
244 * clipboard:</p> | |
245 * | |
246 * <code><pre> | |
247 * Clipboard clipboard = new Clipboard(display); | |
248 * TextTransfer textTransfer = TextTransfer.getInstance(); | |
249 * String textData = (String)clipboard.getContents(textTransfer); | |
250 * if (textData !is null) System.out.println("Text is "+textData); | |
251 * RTFTransfer rtfTransfer = RTFTransfer.getInstance(); | |
252 * String rtfData = (String)clipboard.getContents(rtfTransfer); | |
253 * if (rtfData !is null) System.out.println("RTF Text is "+rtfData); | |
254 * clipboard.dispose(); | |
255 * </code></pre> | |
256 * | |
257 * @param transfer the transfer agent for the type of data being requested | |
258 * @return the data obtained from the clipboard or null if no data of this type is available | |
259 * | |
260 * @exception SWTException <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 */ | |
270 public Object getContents(Transfer transfer) { | |
271 return getContents(transfer, DND.CLIPBOARD); | |
272 } | |
273 /** | |
274 * Retrieve the data of the specified type currently available on the specified | |
275 * clipboard. Refer to the specific subclass of <code>Transfer</code> to | |
276 * determine the type of object returned. | |
277 * | |
278 * <p>The following snippet shows text and RTF text being retrieved from the | |
279 * clipboard:</p> | |
280 * | |
281 * <code><pre> | |
282 * Clipboard clipboard = new Clipboard(display); | |
283 * TextTransfer textTransfer = TextTransfer.getInstance(); | |
284 * String textData = (String)clipboard.getContents(textTransfer); | |
285 * if (textData !is null) System.out.println("Text is "+textData); | |
286 * RTFTransfer rtfTransfer = RTFTransfer.getInstance(); | |
287 * String rtfData = (String)clipboard.getContents(rtfTransfer, DND.CLIPBOARD); | |
288 * if (rtfData !is null) System.out.println("RTF Text is "+rtfData); | |
289 * clipboard.dispose(); | |
290 * </code></pre> | |
291 * | |
292 * <p>The clipboards value is either one of the clipboard constants defined in | |
293 * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together | |
294 * (that is, using the <code>int</code> "|" operator) two or more | |
295 * of those <code>DND</code> clipboard constants.</p> | |
296 * | |
297 * @param transfer the transfer agent for the type of data being requested | |
298 * @param clipboards on which to look for data | |
299 * | |
300 * @return the data obtained from the clipboard or null if no data of this type is available | |
301 * | |
302 * @exception SWTException <ul> | |
303 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
304 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
305 * </ul> | |
306 * @exception IllegalArgumentException <ul> | |
307 * <li>ERROR_NULL_ARGUMENT - if transfer is null</li> | |
308 * </ul> | |
309 * | |
310 * @see Transfer | |
311 * @see DND#CLIPBOARD | |
312 * @see DND#SELECTION_CLIPBOARD | |
313 * | |
314 * @since 3.1 | |
315 */ | |
316 public Object getContents(Transfer transfer, int clipboards) { | |
317 checkWidget(); | |
318 if (transfer is null) DND.error(SWT.ERROR_NULL_ARGUMENT); | |
319 if ((clipboards & DND.CLIPBOARD) is 0) return null; | |
320 /* | |
321 * Bug in Windows. When a new application takes control | |
322 * of the clipboard, other applications may open the | |
323 * clipboard to determine if they want to record the | |
324 * clipboard updates. When this happens, the clipboard | |
325 * can not be accessed until the other application is | |
326 * finished. To allow the other applications to release | |
327 * the clipboard, use PeekMessage() to enable cross thread | |
328 * message sends. | |
329 */ | |
330 IDataObject dataObject; | |
331 int retryCount = 0; | |
332 /* OleGetClipboard([out] ppDataObject). | |
333 * AddRef has already been called on ppDataObject by the callee and must be released by the caller. | |
334 */ | |
335 int result = COM.OleGetClipboard(&dataObject); | |
336 while (result !is COM.S_OK && retryCount++ < 10) { | |
337 try {Thread.sleep(0.050);} catch (Exception t) {} | |
338 MSG msg; | |
339 OS.PeekMessage(&msg, null, 0, 0, OS.PM_NOREMOVE | OS.PM_NOYIELD); | |
340 result = COM.OleGetClipboard(&dataObject); | |
341 } | |
342 if (result !is COM.S_OK) return null; | |
343 try { | |
344 TransferData[] allowed = transfer.getSupportedTypes(); | |
345 for (int i = 0; i < allowed.length; i++) { | |
346 if (dataObject.QueryGetData(allowed[i].formatetc) is COM.S_OK) { | |
347 TransferData data = allowed[i]; | |
348 data.pIDataObject = dataObject; | |
349 return transfer.nativeToJava(data); | |
350 } | |
351 } | |
352 } finally { | |
353 dataObject.Release(); | |
354 } | |
355 return null; // No data available for this transfer | |
356 } | |
357 /** | |
358 * Returns <code>true</code> if the clipboard has been disposed, | |
359 * and <code>false</code> otherwise. | |
360 * <p> | |
361 * This method gets the dispose state for the clipboard. | |
362 * When a clipboard has been disposed, it is an error to | |
363 * invoke any other method using the clipboard. | |
364 * </p> | |
365 * | |
366 * @return <code>true</code> when the widget is disposed and <code>false</code> otherwise | |
367 * | |
368 * @since 3.0 | |
369 */ | |
370 public bool isDisposed () { | |
371 return (display is null); | |
372 } | |
373 | |
374 /** | |
375 * Place data of the specified type on the system clipboard. More than one type | |
376 * of data can be placed on the system clipboard at the same time. Setting the | |
377 * data clears any previous data from the system clipboard, regardless of type. | |
378 * | |
379 * <p>NOTE: On some platforms, the data is immediately copied to the system | |
380 * clipboard but on other platforms it is provided upon request. As a result, | |
381 * if the application modifies the data object it has set on the clipboard, that | |
382 * modification may or may not be available when the data is subsequently | |
383 * requested.</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); | |
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 * | |
406 * @exception IllegalArgumentException <ul> | |
407 * <li>ERROR_INVALID_ARGUMENT - if data is null or datatypes is null | |
408 * or the length of data is not the same as the length of dataTypes</li> | |
409 * </ul> | |
410 * @exception SWTException <ul> | |
411 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
412 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
413 * </ul> | |
414 * @exception SWTError <ul> | |
415 * <li>ERROR_CANNOT_SET_CLIPBOARD - if the clipboard is locked or otherwise unavailable</li> | |
416 * </ul> | |
417 * | |
418 * <p>NOTE: ERROR_CANNOT_SET_CLIPBOARD should be an SWTException, since it is a | |
419 * recoverable error, but can not be changed due to backward compatibility.</p> | |
420 */ | |
421 public void setContents(Object[] data, Transfer[] dataTypes) { | |
422 setContents(data, dataTypes, DND.CLIPBOARD); | |
423 } | |
424 | |
425 /** | |
426 * Place data of the specified type on the specified clipboard. More than one | |
427 * type of data can be placed on the specified clipboard at the same time. | |
428 * Setting the data clears any previous data from the specified | |
429 * clipboard, regardless of type. | |
430 * | |
431 * <p>NOTE: On some platforms, the data is immediately copied to the specified | |
432 * clipboard but on other platforms it is provided upon request. As a result, | |
433 * if the application modifies the data object it has set on the clipboard, that | |
434 * modification may or may not be available when the data is subsequently | |
435 * requested.</p> | |
436 * | |
437 * <p>The clipboards value is either one of the clipboard constants defined in | |
438 * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together | |
439 * (that is, using the <code>int</code> "|" operator) two or more | |
440 * of those <code>DND</code> clipboard constants.</p> | |
441 * | |
442 * <p>The following snippet shows text and RTF text being set on the copy/paste | |
443 * clipboard: | |
444 * </p> | |
445 * | |
446 * <code><pre> | |
447 * Clipboard clipboard = new Clipboard(display); | |
448 * String textData = "Hello World"; | |
449 * String rtfData = "{\\rtf1\\b\\i Hello World}"; | |
450 * TextTransfer textTransfer = TextTransfer.getInstance(); | |
451 * RTFTransfer rtfTransfer = RTFTransfer.getInstance(); | |
452 * Transfer[] transfers = new Transfer[]{textTransfer, rtfTransfer}; | |
453 * Object[] data = new Object[]{textData, rtfData}; | |
454 * clipboard.setContents(data, transfers, DND.CLIPBOARD); | |
455 * clipboard.dispose(); | |
456 * </code></pre> | |
457 * | |
458 * @param data the data to be set in the clipboard | |
459 * @param dataTypes the transfer agents that will convert the data to its | |
460 * platform specific format; each entry in the data array must have a | |
461 * corresponding dataType | |
462 * @param clipboards on which to set the data | |
463 * | |
464 * @exception IllegalArgumentException <ul> | |
465 * <li>ERROR_INVALID_ARGUMENT - if data is null or datatypes is null | |
466 * or the length of data is not the same as the length of dataTypes</li> | |
467 * </ul> | |
468 * @exception SWTException <ul> | |
469 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
470 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
471 * </ul> | |
472 * @exception SWTError <ul> | |
473 * <li>ERROR_CANNOT_SET_CLIPBOARD - if the clipboard is locked or otherwise unavailable</li> | |
474 * </ul> | |
475 * | |
476 * <p>NOTE: ERROR_CANNOT_SET_CLIPBOARD should be an SWTException, since it is a | |
477 * recoverable error, but can not be changed due to backward compatibility.</p> | |
478 * | |
479 * @see DND#CLIPBOARD | |
480 * @see DND#SELECTION_CLIPBOARD | |
481 * | |
482 * @since 3.1 | |
483 */ | |
484 public void setContents(Object[] data, Transfer[] dataTypes, int clipboards) { | |
485 checkWidget(); | |
486 if (data is null || dataTypes is null || data.length !is dataTypes.length || data.length is 0) { | |
487 DND.error(SWT.ERROR_INVALID_ARGUMENT); | |
488 } | |
489 for (int i = 0; i < data.length; i++) { | |
490 if (data[i] is null || dataTypes[i] is null || !dataTypes[i].validate(data[i])) { | |
491 DND.error(SWT.ERROR_INVALID_ARGUMENT); | |
492 } | |
493 } | |
494 if ((clipboards & DND.CLIPBOARD) is 0) return; | |
495 this.data = data; | |
496 this.transferAgents = dataTypes; | |
497 /* OleSetClipboard([in] pDataObject) | |
498 * The argument pDataObject is owned by the caller so the reference count does not | |
499 * need to be incremented. | |
500 */ | |
501 int result = COM.OleSetClipboard(iDataObject); | |
502 | |
503 /* | |
504 * Bug in Windows. When a new application takes control | |
505 * of the clipboard, other applications may open the | |
506 * clipboard to determine if they want to record the | |
507 * clipboard updates. When this happens, the clipboard | |
508 * can not be flushed until the other application is | |
509 * finished. To allow other applications to get the | |
510 * data, use PeekMessage() to enable cross thread | |
511 * message sends. | |
512 */ | |
513 int retryCount = 0; | |
514 while (result !is COM.S_OK && retryCount++ < 10) { | |
515 try {Thread.sleep(0.050);} catch (Exception t) {} | |
516 MSG msg; | |
517 OS.PeekMessage(&msg, null, 0, 0, OS.PM_NOREMOVE | OS.PM_NOYIELD); | |
518 result = COM.OleSetClipboard(iDataObject); | |
519 } | |
520 if (result !is COM.S_OK) { | |
521 DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD); | |
522 } | |
523 } | |
524 private int AddRef() { | |
525 refCount++; | |
526 return refCount; | |
527 } | |
528 private void createCOMInterfaces() { | |
529 // register each of the interfaces that this object implements | |
530 iDataObject = new _IDataObjectImpl( this ); | |
531 } | |
532 private void disposeCOMInterfaces() { | |
533 iDataObject = null; | |
534 } | |
535 /* | |
536 * EnumFormatEtc([in] dwDirection, [out] ppenumFormatetc) | |
537 * Ownership of ppenumFormatetc transfers from callee to caller so reference count on ppenumFormatetc | |
538 * must be incremented before returning. Caller is responsible for releasing ppenumFormatetc. | |
539 */ | |
540 LRESULT EnumFormatEtc(int dwDirection, IEnumFORMATETC* ppenumFormatetc) { | |
541 // only allow getting of data - SetData is not currently supported | |
542 if (dwDirection is COM.DATADIR_SET) return COM.E_NOTIMPL; | |
543 // what types have been registered? | |
544 TransferData[] allowedDataTypes = new TransferData[0]; | |
545 for (int i = 0; i < transferAgents.length; i++){ | |
546 TransferData[] formats = transferAgents[i].getSupportedTypes(); | |
547 TransferData[] newAllowedDataTypes = new TransferData[allowedDataTypes.length + formats.length]; | |
548 System.arraycopy(allowedDataTypes, 0, newAllowedDataTypes, 0, allowedDataTypes.length); | |
549 System.arraycopy(formats, 0, newAllowedDataTypes, allowedDataTypes.length, formats.length); | |
550 allowedDataTypes = newAllowedDataTypes; | |
551 } | |
552 OleEnumFORMATETC enumFORMATETC = new OleEnumFORMATETC(); | |
553 enumFORMATETC.AddRef(); | |
554 FORMATETC*[] formats = new FORMATETC*[allowedDataTypes.length + 1]; | |
555 for (int i = 0; i < allowedDataTypes.length; i++){ | |
556 formats[i] = allowedDataTypes[i].formatetc; | |
557 } | |
558 // include the drop effect format to specify a copy operation | |
559 FORMATETC* dropeffect = new FORMATETC(); | |
560 dropeffect.cfFormat = CFSTR_PREFERREDDROPEFFECT; | |
561 dropeffect.dwAspect = COM.DVASPECT_CONTENT; | |
562 dropeffect.lindex = -1; | |
563 dropeffect.tymed = COM.TYMED_HGLOBAL; | |
564 formats[formats.length -1] = dropeffect; | |
565 enumFORMATETC.setFormats(formats); | |
566 | |
567 // TODO: <shawn liu> do we need AddRef() here | |
568 *ppenumFormatetc = enumFORMATETC.getAddress(); | |
569 return COM.S_OK; | |
570 } | |
571 | |
572 private IDataObject getAddress(){ | |
573 return iDataObject; | |
574 } | |
575 | |
576 LRESULT GetData(FORMATETC *pFormatetc, STGMEDIUM *pmedium) { | |
577 /* Called by a data consumer to obtain data from a source data object. | |
578 The GetData method renders the data described in the specified FORMATETC | |
579 structure and transfers it through the specified STGMEDIUM structure. | |
580 The caller then assumes responsibility for releasing the STGMEDIUM structure. | |
581 */ | |
582 if (pFormatetc is null || pmedium is null) return COM.E_INVALIDARG; | |
583 if (QueryGetData(pFormatetc) !is COM.S_OK) return COM.DV_E_FORMATETC; | |
584 | |
585 TransferData transferData = new TransferData(); | |
586 transferData.formatetc = new FORMATETC(); | |
587 COM.MoveMemory(transferData.formatetc, pFormatetc, FORMATETC.sizeof); | |
588 transferData.type = transferData.formatetc.cfFormat; | |
589 transferData.stgmedium = new STGMEDIUM(); | |
590 transferData.result = COM.E_FAIL; | |
591 | |
592 if (transferData.type is CFSTR_PREFERREDDROPEFFECT) { | |
593 // specify that a copy operation is to be performed | |
594 STGMEDIUM* stgmedium = new STGMEDIUM(); | |
595 stgmedium.tymed = COM.TYMED_HGLOBAL; | |
596 stgmedium.unionField = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, 4); | |
597 //TODO - should call GlobalLock | |
598 stgmedium.unionField = cast(void*)COM.DROPEFFECT_COPY; | |
599 stgmedium.pUnkForRelease = null; | |
600 COM.MoveMemory(pmedium, stgmedium, STGMEDIUM.sizeof); | |
601 return COM.S_OK; | |
602 } | |
603 | |
604 // get matching transfer agent to perform conversion | |
605 int transferIndex = -1; | |
606 for (int i = 0; i < transferAgents.length; i++){ | |
607 if (transferAgents[i].isSupportedType(transferData)){ | |
608 transferIndex = i; | |
609 break; | |
610 } | |
611 } | |
612 if (transferIndex is -1) return COM.DV_E_FORMATETC; | |
613 transferAgents[transferIndex].javaToNative(data[transferIndex], transferData); | |
614 COM.MoveMemory(pmedium, transferData.stgmedium, STGMEDIUM.sizeof); | |
615 return transferData.result; | |
616 } | |
617 | |
618 LRESULT QueryGetData(FORMATETC * pFormatetc) { | |
619 if (transferAgents is null) return COM.E_FAIL; | |
620 TransferData transferData = new TransferData(); | |
621 transferData.formatetc = new FORMATETC(); | |
622 COM.MoveMemory(transferData.formatetc, pFormatetc, FORMATETC.sizeof); | |
623 transferData.type = transferData.formatetc.cfFormat; | |
624 if (transferData.type is CFSTR_PREFERREDDROPEFFECT) return COM.S_OK; | |
625 // is this type supported by the transfer agent? | |
626 for (int i = 0; i < transferAgents.length; i++){ | |
627 if (transferAgents[i].isSupportedType(transferData)) | |
628 return COM.S_OK; | |
629 } | |
630 | |
631 return COM.DV_E_FORMATETC; | |
632 } | |
633 /* QueryInterface([in] iid, [out] ppvObject) | |
634 * Ownership of ppvObject transfers from callee to caller so reference count on ppvObject | |
635 * must be incremented before returning. Caller is responsible for releasing ppvObject. | |
636 */ | |
637 HRESULT QueryInterface(GUID* riid, void ** ppvObject) { | |
638 if (riid is null || ppvObject is null) return COM.E_INVALIDARG; | |
639 if (COM.IsEqualGUID(riid, &COM.IIDIUnknown) || COM.IsEqualGUID(riid, &COM.IIDIDataObject) ) { | |
640 *ppvObject = cast(void*)cast(IUnknown)iDataObject; | |
641 AddRef(); | |
642 return COM.S_OK; | |
643 } | |
644 *ppvObject = null; | |
645 return COM.E_NOINTERFACE; | |
646 } | |
647 private ULONG Release() { | |
648 refCount--; | |
649 if (refCount is 0) { | |
650 this.data = null; | |
651 this.transferAgents = null; | |
652 disposeCOMInterfaces(); | |
653 COM.CoFreeUnusedLibraries(); | |
654 } | |
655 return refCount; | |
656 } | |
657 | |
658 /** | |
659 * Returns an array of the data types currently available on the system | |
660 * clipboard. Use with Transfer.isSupportedType. | |
661 * | |
662 * @return array of data types currently available on the system clipboard | |
663 * | |
664 * @exception SWTException <ul> | |
665 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
666 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
667 * </ul> | |
668 * | |
669 * @see Transfer#isSupportedType | |
670 * | |
671 * @since 3.0 | |
672 */ | |
673 public TransferData[] getAvailableTypes() { | |
674 return getAvailableTypes(DND.CLIPBOARD); | |
675 } | |
676 | |
677 /** | |
678 * Returns an array of the data types currently available on the specified | |
679 * clipboard. Use with Transfer.isSupportedType. | |
680 * | |
681 * <p>The clipboards value is either one of the clipboard constants defined in | |
682 * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together | |
683 * (that is, using the <code>int</code> "|" operator) two or more | |
684 * of those <code>DND</code> clipboard constants.</p> | |
685 * | |
686 * @param clipboards from which to get the data types | |
687 * @return array of data types currently available on the specified clipboard | |
688 * | |
689 * @exception SWTException <ul> | |
690 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
691 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
692 * </ul> | |
693 * | |
694 * @see Transfer#isSupportedType | |
695 * @see DND#CLIPBOARD | |
696 * @see DND#SELECTION_CLIPBOARD | |
697 * | |
698 * @since 3.1 | |
699 */ | |
700 public TransferData[] getAvailableTypes(int clipboards) { | |
701 checkWidget(); | |
702 if ((clipboards & DND.CLIPBOARD) is 0) return null; | |
703 FORMATETC*[] types = _getAvailableTypes(); | |
704 TransferData[] data = new TransferData[types.length]; | |
705 for (int i = 0; i < types.length; i++) { | |
706 data[i] = new TransferData(); | |
707 data[i].type = types[i].cfFormat; | |
708 data[i].formatetc = types[i]; | |
709 } | |
710 return data; | |
711 } | |
712 | |
713 /** | |
714 * Returns a platform specific list of the data types currently available on the | |
715 * system clipboard. | |
716 * | |
717 * <p>Note: <code>getAvailableTypeNames</code> is a utility for writing a Transfer | |
718 * sub-class. It should NOT be used within an application because it provides | |
719 * platform specific information.</p> | |
720 * | |
721 * @return a platform specific list of the data types currently available on the | |
722 * system clipboard | |
723 * | |
724 * @exception SWTException <ul> | |
725 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
726 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
727 * </ul> | |
728 */ | |
729 public String[] getAvailableTypeNames() { | |
730 checkWidget(); | |
731 FORMATETC*[] types = _getAvailableTypes(); | |
732 String[] names = new String[](types.length); | |
733 int maxSize = 128; | |
734 for (int i = 0; i < types.length; i++){ | |
735 TCHAR[] buffer = NewTCHARs(0, maxSize); | |
736 int size = OS.GetClipboardFormatName(types[i].cfFormat, buffer.ptr, maxSize); | |
737 if (size !is 0) { | |
738 names[i] = TCHARzToStr(buffer.ptr)[0..size]; | |
739 } else { | |
740 switch (types[i].cfFormat) { | |
741 case COM.CF_HDROP: names[i] = "CF_HDROP"; break; //$NON-NLS-1$ | |
742 case COM.CF_TEXT: names[i] = "CF_TEXT"; break; //$NON-NLS-1$ | |
743 case COM.CF_BITMAP: names[i] = "CF_BITMAP"; break; //$NON-NLS-1$ | |
744 case COM.CF_METAFILEPICT: names[i] = "CF_METAFILEPICT"; break; //$NON-NLS-1$ | |
745 case COM.CF_SYLK: names[i] = "CF_SYLK"; break; //$NON-NLS-1$ | |
746 case COM.CF_DIF: names[i] = "CF_DIF"; break; //$NON-NLS-1$ | |
747 case COM.CF_TIFF: names[i] = "CF_TIFF"; break; //$NON-NLS-1$ | |
748 case COM.CF_OEMTEXT: names[i] = "CF_OEMTEXT"; break; //$NON-NLS-1$ | |
749 case COM.CF_DIB: names[i] = "CF_DIB"; break; //$NON-NLS-1$ | |
750 case COM.CF_PALETTE: names[i] = "CF_PALETTE"; break; //$NON-NLS-1$ | |
751 case COM.CF_PENDATA: names[i] = "CF_PENDATA"; break; //$NON-NLS-1$ | |
752 case COM.CF_RIFF: names[i] = "CF_RIFF"; break; //$NON-NLS-1$ | |
753 case COM.CF_WAVE: names[i] = "CF_WAVE"; break; //$NON-NLS-1$ | |
754 case COM.CF_UNICODETEXT: names[i] = "CF_UNICODETEXT"; break; //$NON-NLS-1$ | |
755 case COM.CF_ENHMETAFILE: names[i] = "CF_ENHMETAFILE"; break; //$NON-NLS-1$ | |
756 case COM.CF_LOCALE: names[i] = "CF_LOCALE"; break; //$NON-NLS-1$ | |
757 case COM.CF_MAX: names[i] = "CF_MAX"; break; //$NON-NLS-1$ | |
758 default: names[i] = "UNKNOWN"; //$NON-NLS-1$ | |
759 } | |
760 } | |
761 } | |
762 return names; | |
763 } | |
764 | |
765 private FORMATETC*[] _getAvailableTypes() { | |
766 FORMATETC*[] types = null; | |
767 IDataObject dataObject; | |
768 /* OleGetClipboard([out] ppDataObject). | |
769 * AddRef has already been called on ppDataObject by the callee and must be released by the caller. | |
770 */ | |
771 if (COM.OleGetClipboard(&dataObject) !is COM.S_OK) return types; | |
772 IEnumFORMATETC enumFormatetc; | |
773 /* EnumFormatEtc([in] dwDirection, [out] ppenumFormatetc) | |
774 * AddRef has already been called on ppenumFormatetc by the callee and must be released by the caller. | |
775 */ | |
776 int rc = dataObject.EnumFormatEtc(COM.DATADIR_GET, &enumFormatetc); | |
777 dataObject.Release(); | |
778 if (rc !is COM.S_OK)return types; | |
779 // Loop over enumerator and save any types that match what we are looking for | |
780 //int /*long*/ rgelt = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, FORMATETC.sizeof); | |
781 uint[1] pceltFetched; | |
782 FORMATETC rgelt; | |
783 enumFormatetc.Reset(); | |
784 while (enumFormatetc.Next(1, &rgelt, pceltFetched.ptr) is COM.S_OK && pceltFetched[0] is 1) { | |
785 FORMATETC* formatetc = new FORMATETC(); | |
786 COM.MoveMemory(formatetc, &rgelt, FORMATETC.sizeof); | |
787 FORMATETC*[] newTypes = new FORMATETC*[types.length + 1]; | |
788 SimpleType!(FORMATETC*).arraycopy(types, 0, newTypes, 0, types.length); | |
789 newTypes[types.length] = formatetc; | |
790 types = newTypes; | |
791 } | |
792 //OS.GlobalFree(rgelt); | |
793 enumFormatetc.Release(); | |
794 return types; | |
795 } | |
796 } | |
797 | |
798 private class _IDataObjectImpl : IDataObject { | |
799 | |
800 Clipboard parent; | |
801 this(Clipboard p) { parent = p; } | |
802 extern (Windows): | |
803 // interface of IUnknown | |
804 HRESULT QueryInterface(GUID* riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); } | |
805 ULONG AddRef() { return parent.AddRef(); } | |
806 ULONG Release() { return parent.Release(); } | |
807 | |
808 // interface IDataObject | |
809 LRESULT GetData( FORMATETC *pFormatetc, STGMEDIUM *pmedium) { return parent.GetData(pFormatetc, pmedium); } | |
810 LRESULT GetDataHere(FORMATETC * pFormatetc, STGMEDIUM * pmedium) { return COM.E_NOTIMPL; } | |
811 LRESULT QueryGetData(FORMATETC* pFormatetc) { return parent.QueryGetData(pFormatetc); } | |
812 LRESULT GetCanonicalFormatEtc(FORMATETC* pFormatetcIn, FORMATETC* pFormatetcOut) { return COM.E_NOTIMPL; } | |
813 LRESULT SetData(FORMATETC* pFormatetc, STGMEDIUM * pmedium, BOOL fRelease) { return COM.E_NOTIMPL; } | |
814 LRESULT EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC * ppenumFormatetc) { return parent.EnumFormatEtc(dwDirection, ppenumFormatetc); } | |
815 LRESULT DAdvise(FORMATETC* pFormatetc, DWORD advf, IAdviseSink pAdvSink, DWORD* pdwConnection) { return COM.E_NOTIMPL; } | |
816 LRESULT DUnadvise(DWORD dwConnection) { return COM.E_NOTIMPL; } | |
817 LRESULT EnumDAdvise(IEnumSTATDATA * ppenumAdvise) { return COM.E_NOTIMPL; } | |
818 } | |
819 |