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