KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > swt > dnd > Clipboard


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 package org.eclipse.swt.dnd;
12
13
14 import org.eclipse.swt.*;
15 import org.eclipse.swt.widgets.*;
16 import org.eclipse.swt.internal.win32.*;
17 import org.eclipse.swt.internal.ole.win32.*;
18
19 /**
20  * The <code>Clipboard</code> provides a mechanism for transferring data from one
21  * application to another or within an application.
22  *
23  * <p>IMPORTANT: This class is <em>not</em> intended to be subclassed.</p>
24  */

25 public class Clipboard {
26
27     private Display display;
28     
29     // ole interfaces
30
private COMObject iDataObject;
31     private int refCount;
32     private Transfer[] transferAgents = new Transfer[0];
33     private Object JavaDoc[] data = new Object JavaDoc[0];
34     private int CFSTR_PREFERREDDROPEFFECT;
35
36 /**
37  * Constructs a new instance of this class. Creating an instance of a Clipboard
38  * may cause system resources to be allocated depending on the platform. It is therefore
39  * mandatory that the Clipboard instance be disposed when no longer required.
40  *
41  * @param display the display on which to allocate the clipboard
42  *
43  * @exception SWTException <ul>
44  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
45  * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
46  * </ul>
47  *
48  * @see Clipboard#dispose
49  * @see Clipboard#checkSubclass
50  */

51 public Clipboard(Display display) {
52     checkSubclass ();
53     if (display == null) {
54         display = Display.getCurrent();
55         if (display == null) {
56             display = Display.getDefault();
57         }
58     }
59     if (display.getThread() != Thread.currentThread()) {
60         DND.error(SWT.ERROR_THREAD_INVALID_ACCESS);
61     }
62     this.display = display;
63     TCHAR chFormatName = new TCHAR(0, "Preferred DropEffect", true); //$NON-NLS-1$
64
CFSTR_PREFERREDDROPEFFECT = OS.RegisterClipboardFormat(chFormatName);
65     createCOMInterfaces();
66     this.AddRef();
67 }
68
69 /**
70  * Checks that this class can be subclassed.
71  * <p>
72  * The SWT class library is intended to be subclassed
73  * only at specific, controlled points. This method enforces this
74  * rule unless it is overridden.
75  * </p><p>
76  * <em>IMPORTANT:</em> By providing an implementation of this
77  * method that allows a subclass of a class which does not
78  * normally allow subclassing to be created, the implementer
79  * agrees to be fully responsible for the fact that any such
80  * subclass will likely fail between SWT releases and will be
81  * strongly platform specific. No support is provided for
82  * user-written classes which are implemented in this fashion.
83  * </p><p>
84  * The ability to subclass outside of the allowed SWT classes
85  * is intended purely to enable those not on the SWT development
86  * team to implement patches in order to get around specific
87  * limitations in advance of when those limitations can be
88  * addressed by the team. Subclassing should not be attempted
89  * without an intimate and detailed understanding of the hierarchy.
90  * </p>
91  *
92  * @exception SWTException <ul>
93  * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
94  * </ul>
95  */

96 protected void checkSubclass () {
97     String JavaDoc name = getClass().getName ();
98     String JavaDoc validName = Clipboard.class.getName();
99     if (!validName.equals(name)) {
100         DND.error (SWT.ERROR_INVALID_SUBCLASS);
101     }
102 }
103
104 /**
105  * Throws an <code>SWTException</code> if the receiver can not
106  * be accessed by the caller. This may include both checks on
107  * the state of the receiver and more generally on the entire
108  * execution context. This method <em>should</em> be called by
109  * widget implementors to enforce the standard SWT invariants.
110  * <p>
111  * Currently, it is an error to invoke any method (other than
112  * <code>isDisposed()</code>) on a widget that has had its
113  * <code>dispose()</code> method called. It is also an error
114  * to call widget methods from any thread that is different
115  * from the thread that created the widget.
116  * </p><p>
117  * In future releases of SWT, there may be more or fewer error
118  * checks and exceptions may be thrown for different reasons.
119  * </p>
120  *
121  * @exception SWTException <ul>
122  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
123  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
124  * </ul>
125  */

126 protected void checkWidget () {
127     Display display = this.display;
128     if (display == null) DND.error (SWT.ERROR_WIDGET_DISPOSED);
129     if (display.getThread() != Thread.currentThread ()) DND.error (SWT.ERROR_THREAD_INVALID_ACCESS);
130     if (display.isDisposed()) DND.error(SWT.ERROR_WIDGET_DISPOSED);
131 }
132
133 /**
134  * If this clipboard is currently the owner of the data on the system clipboard,
135  * clear the contents. If this clipboard is not the owner, then nothing is done.
136  * Note that there are clipboard assistant applications that take ownership of
137  * data or make copies of data when it is placed on the clipboard. In these
138  * cases, it may not be possible to clear the clipboard.
139  *
140  * @exception SWTException <ul>
141  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
142  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
143  * </ul>
144  *
145  * @since 3.1
146  */

147 public void clearContents() {
148     clearContents(DND.CLIPBOARD);
149 }
150
151 /**
152  * If this clipboard is currently the owner of the data on the specified
153  * clipboard, clear the contents. If this clipboard is not the owner, then
154  * nothing is done.
155  *
156  * <p>Note that there are clipboard assistant applications that take ownership
157  * of data or make copies of data when it is placed on the clipboard. In these
158  * cases, it may not be possible to clear the clipboard.</p>
159  *
160  * <p>The clipboards value is either one of the clipboard constants defined in
161  * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
162  * (that is, using the <code>int</code> "|" operator) two or more
163  * of those <code>DND</code> clipboard constants.</p>
164  *
165  * @param clipboards to be cleared
166  *
167  * @exception SWTException <ul>
168  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
169  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
170  * </ul>
171  *
172  * @see DND#CLIPBOARD
173  * @see DND#SELECTION_CLIPBOARD
174  *
175  * @since 3.1
176  */

177 public void clearContents(int clipboards) {
178     checkWidget();
179     if ((clipboards & DND.CLIPBOARD) != 0) {
180         /* OleIsCurrentClipboard([in] pDataObject)
181          * The argument pDataObject is owned by the caller so reference count does not
182          * need to be incremented.
183          */

184         if (COM.OleIsCurrentClipboard(this.iDataObject.getAddress()) == COM.S_OK) {
185             /* OleSetClipboard([in] pDataObject)
186              * The argument pDataObject is owned by the caller so reference count does not
187              * need to be incremented.
188              */

189             COM.OleSetClipboard(0);
190         }
191     }
192 }
193
194 /**
195  * Disposes of the operating system resources associated with the clipboard.
196  * The data will still be available on the system clipboard after the dispose
197  * method is called.
198  *
199  * <p>NOTE: On some platforms the data will not be available once the application
200  * has exited or the display has been disposed.</p>
201  *
202  * @exception SWTException <ul>
203  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
204  * </ul>
205  */

206 public void dispose () {
207     if (isDisposed()) return;
208     if (display.getThread() != Thread.currentThread()) DND.error(SWT.ERROR_THREAD_INVALID_ACCESS);
209     /* OleIsCurrentClipboard([in] pDataObject)
210      * The argument pDataObject is owned by the caller so reference count does not
211      * need to be incremented.
212      */

213     if (COM.OleIsCurrentClipboard(this.iDataObject.getAddress()) == COM.S_OK) {
214         COM.OleFlushClipboard();
215     }
216     this.Release();
217     display = null;
218 }
219
220 /**
221  * Retrieve the data of the specified type currently available on the system
222  * clipboard. Refer to the specific subclass of <code>Transfer</code> to
223  * determine the type of object returned.
224  *
225  * <p>The following snippet shows text and RTF text being retrieved from the
226  * clipboard:</p>
227  *
228  * <code><pre>
229  * Clipboard clipboard = new Clipboard(display);
230  * TextTransfer textTransfer = TextTransfer.getInstance();
231  * String textData = (String)clipboard.getContents(textTransfer);
232  * if (textData != null) System.out.println("Text is "+textData);
233  * RTFTransfer rtfTransfer = RTFTransfer.getInstance();
234  * String rtfData = (String)clipboard.getContents(rtfTransfer);
235  * if (rtfData != null) System.out.println("RTF Text is "+rtfData);
236  * clipboard.dispose();
237  * </code></pre>
238  *
239  * @param transfer the transfer agent for the type of data being requested
240  * @return the data obtained from the clipboard or null if no data of this type is available
241  *
242  * @exception SWTException <ul>
243  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
244  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
245  * </ul>
246  * @exception IllegalArgumentException <ul>
247  * <li>ERROR_NULL_ARGUMENT - if transfer is null</li>
248  * </ul>
249  *
250  * @see Transfer
251  */

252 public Object JavaDoc getContents(Transfer transfer) {
253     return getContents(transfer, DND.CLIPBOARD);
254 }
255 /**
256  * Retrieve the data of the specified type currently available on the specified
257  * clipboard. Refer to the specific subclass of <code>Transfer</code> to
258  * determine the type of object returned.
259  *
260  * <p>The following snippet shows text and RTF text being retrieved from the
261  * clipboard:</p>
262  *
263  * <code><pre>
264  * Clipboard clipboard = new Clipboard(display);
265  * TextTransfer textTransfer = TextTransfer.getInstance();
266  * String textData = (String)clipboard.getContents(textTransfer);
267  * if (textData != null) System.out.println("Text is "+textData);
268  * RTFTransfer rtfTransfer = RTFTransfer.getInstance();
269  * String rtfData = (String)clipboard.getContents(rtfTransfer, DND.CLIPBOARD);
270  * if (rtfData != null) System.out.println("RTF Text is "+rtfData);
271  * clipboard.dispose();
272  * </code></pre>
273  *
274  * <p>The clipboards value is either one of the clipboard constants defined in
275  * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
276  * (that is, using the <code>int</code> "|" operator) two or more
277  * of those <code>DND</code> clipboard constants.</p>
278  *
279  * @param transfer the transfer agent for the type of data being requested
280  * @param clipboards on which to look for data
281  *
282  * @return the data obtained from the clipboard or null if no data of this type is available
283  *
284  * @exception SWTException <ul>
285  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
286  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
287  * </ul>
288  * @exception IllegalArgumentException <ul>
289  * <li>ERROR_NULL_ARGUMENT - if transfer is null</li>
290  * </ul>
291  *
292  * @see Transfer
293  * @see DND#CLIPBOARD
294  * @see DND#SELECTION_CLIPBOARD
295  *
296  * @since 3.1
297  */

298 public Object JavaDoc getContents(Transfer transfer, int clipboards) {
299     checkWidget();
300     if (transfer == null) DND.error(SWT.ERROR_NULL_ARGUMENT);
301     if ((clipboards & DND.CLIPBOARD) == 0) return null;
302     /*
303     * Bug in Windows. When a new application takes control
304     * of the clipboard, other applications may open the
305     * clipboard to determine if they want to record the
306     * clipboard updates. When this happens, the clipboard
307     * can not be accessed until the other application is
308     * finished. To allow the other applications to release
309     * the clipboard, use PeekMessage() to enable cross thread
310     * message sends.
311     */

312     int[] ppv = new int[1];
313     int retryCount = 0;
314     /* OleGetClipboard([out] ppDataObject).
315      * AddRef has already been called on ppDataObject by the callee and must be released by the caller.
316      */

317     int result = COM.OleGetClipboard(ppv);
318     while (result != COM.S_OK && retryCount++ < 10) {
319         try {Thread.sleep(50);} catch (Throwable JavaDoc t) {}
320         MSG msg = new MSG();
321         OS.PeekMessage(msg, 0, 0, 0, OS.PM_NOREMOVE | OS.PM_NOYIELD);
322         result = COM.OleGetClipboard(ppv);
323     }
324     if (result != COM.S_OK) return null;
325     IDataObject dataObject = new IDataObject(ppv[0]);
326     try {
327         TransferData[] allowed = transfer.getSupportedTypes();
328         for (int i = 0; i < allowed.length; i++) {
329             if (dataObject.QueryGetData(allowed[i].formatetc) == COM.S_OK) {
330                 TransferData data = allowed[i];
331                 data.pIDataObject = ppv[0];
332                 return transfer.nativeToJava(data);
333             }
334         }
335     } finally {
336         dataObject.Release();
337     }
338     return null; // No data available for this transfer
339
}
340 /**
341  * Returns <code>true</code> if the clipboard has been disposed,
342  * and <code>false</code> otherwise.
343  * <p>
344  * This method gets the dispose state for the clipboard.
345  * When a clipboard has been disposed, it is an error to
346  * invoke any other method using the clipboard.
347  * </p>
348  *
349  * @return <code>true</code> when the widget is disposed and <code>false</code> otherwise
350  *
351  * @since 3.0
352  */

353 public boolean isDisposed () {
354     return (display == null);
355 }
356
357 /**
358  * Place data of the specified type on the system clipboard. More than one type
359  * of data can be placed on the system clipboard at the same time. Setting the
360  * data clears any previous data from the system clipboard, regardless of type.
361  *
362  * <p>NOTE: On some platforms, the data is immediately copied to the system
363  * clipboard but on other platforms it is provided upon request. As a result,
364  * if the application modifies the data object it has set on the clipboard, that
365  * modification may or may not be available when the data is subsequently
366  * requested.</p>
367  *
368  * <p>The following snippet shows text and RTF text being set on the copy/paste
369  * clipboard:
370  * </p>
371  *
372  * <code><pre>
373  * Clipboard clipboard = new Clipboard(display);
374  * String textData = "Hello World";
375  * String rtfData = "{\\rtf1\\b\\i Hello World}";
376  * TextTransfer textTransfer = TextTransfer.getInstance();
377  * RTFTransfer rtfTransfer = RTFTransfer.getInstance();
378  * Transfer[] transfers = new Transfer[]{textTransfer, rtfTransfer};
379  * Object[] data = new Object[]{textData, rtfData};
380  * clipboard.setContents(data, transfers);
381  * clipboard.dispose();
382  * </code></pre>
383  *
384  * @param data the data to be set in the clipboard
385  * @param dataTypes the transfer agents that will convert the data to its
386  * platform specific format; each entry in the data array must have a
387  * corresponding dataType
388  *
389  * @exception IllegalArgumentException <ul>
390  * <li>ERROR_INVALID_ARGUMENT - if data is null or datatypes is null
391  * or the length of data is not the same as the length of dataTypes</li>
392  * </ul>
393  * @exception SWTException <ul>
394  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
395  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
396  * </ul>
397  * @exception SWTError <ul>
398  * <li>ERROR_CANNOT_SET_CLIPBOARD - if the clipboard is locked or otherwise unavailable</li>
399  * </ul>
400  *
401  * <p>NOTE: ERROR_CANNOT_SET_CLIPBOARD should be an SWTException, since it is a
402  * recoverable error, but can not be changed due to backward compatibility.</p>
403  */

404 public void setContents(Object JavaDoc[] data, Transfer[] dataTypes) {
405     setContents(data, dataTypes, DND.CLIPBOARD);
406 }
407
408 /**
409  * Place data of the specified type on the specified clipboard. More than one
410  * type of data can be placed on the specified clipboard at the same time.
411  * Setting the data clears any previous data from the specified
412  * clipboard, regardless of type.
413  *
414  * <p>NOTE: On some platforms, the data is immediately copied to the specified
415  * clipboard but on other platforms it is provided upon request. As a result,
416  * if the application modifies the data object it has set on the clipboard, that
417  * modification may or may not be available when the data is subsequently
418  * requested.</p>
419  *
420  * <p>The clipboards value is either one of the clipboard constants defined in
421  * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
422  * (that is, using the <code>int</code> "|" operator) two or more
423  * of those <code>DND</code> clipboard constants.</p>
424  *
425  * <p>The following snippet shows text and RTF text being set on the copy/paste
426  * clipboard:
427  * </p>
428  *
429  * <code><pre>
430  * Clipboard clipboard = new Clipboard(display);
431  * String textData = "Hello World";
432  * String rtfData = "{\\rtf1\\b\\i Hello World}";
433  * TextTransfer textTransfer = TextTransfer.getInstance();
434  * RTFTransfer rtfTransfer = RTFTransfer.getInstance();
435  * Transfer[] transfers = new Transfer[]{textTransfer, rtfTransfer};
436  * Object[] data = new Object[]{textData, rtfData};
437  * clipboard.setContents(data, transfers, DND.CLIPBOARD);
438  * clipboard.dispose();
439  * </code></pre>
440  *
441  * @param data the data to be set in the clipboard
442  * @param dataTypes the transfer agents that will convert the data to its
443  * platform specific format; each entry in the data array must have a
444  * corresponding dataType
445  * @param clipboards on which to set the data
446  *
447  * @exception IllegalArgumentException <ul>
448  * <li>ERROR_INVALID_ARGUMENT - if data is null or datatypes is null
449  * or the length of data is not the same as the length of dataTypes</li>
450  * </ul>
451  * @exception SWTException <ul>
452  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
453  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
454  * </ul>
455  * @exception SWTError <ul>
456  * <li>ERROR_CANNOT_SET_CLIPBOARD - if the clipboard is locked or otherwise unavailable</li>
457  * </ul>
458  *
459  * <p>NOTE: ERROR_CANNOT_SET_CLIPBOARD should be an SWTException, since it is a
460  * recoverable error, but can not be changed due to backward compatibility.</p>
461  *
462  * @see DND#CLIPBOARD
463  * @see DND#SELECTION_CLIPBOARD
464  *
465  * @since 3.1
466  */

467 public void setContents(Object JavaDoc[] data, Transfer[] dataTypes, int clipboards) {
468     checkWidget();
469     if (data == null || dataTypes == null || data.length != dataTypes.length || data.length == 0) {
470         DND.error(SWT.ERROR_INVALID_ARGUMENT);
471     }
472     for (int i = 0; i < data.length; i++) {
473         if (data[i] == null || dataTypes[i] == null || !dataTypes[i].validate(data[i])) {
474             DND.error(SWT.ERROR_INVALID_ARGUMENT);
475         }
476     }
477     if ((clipboards & DND.CLIPBOARD) == 0) return;
478     this.data = data;
479     this.transferAgents = dataTypes;
480     /* OleSetClipboard([in] pDataObject)
481      * The argument pDataObject is owned by the caller so the reference count does not
482      * need to be incremented.
483      */

484     int result = COM.OleSetClipboard(iDataObject.getAddress());
485     
486     /*
487     * Bug in Windows. When a new application takes control
488     * of the clipboard, other applications may open the
489     * clipboard to determine if they want to record the
490     * clipboard updates. When this happens, the clipboard
491     * can not be flushed until the other application is
492     * finished. To allow other applications to get the
493     * data, use PeekMessage() to enable cross thread
494     * message sends.
495     */

496     int retryCount = 0;
497     while (result != COM.S_OK && retryCount++ < 10) {
498         try {Thread.sleep(50);} catch (Throwable JavaDoc t) {}
499         MSG msg = new MSG();
500         OS.PeekMessage(msg, 0, 0, 0, OS.PM_NOREMOVE | OS.PM_NOYIELD);
501         result = COM.OleSetClipboard(iDataObject.getAddress());
502     }
503     if (result != COM.S_OK) {
504         DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD);
505     }
506 }
507 private int AddRef() {
508     refCount++;
509     return refCount;
510 }
511 private void createCOMInterfaces() {
512     // register each of the interfaces that this object implements
513
iDataObject = new COMObject(new int[]{2, 0, 0, 2, 2, 1, 2, 3, 2, 4, 1, 1}){
514         public int method0(int[] args) {return QueryInterface(args[0], args[1]);}
515         public int method1(int[] args) {return AddRef();}
516         public int method2(int[] args) {return Release();}
517         public int method3(int[] args) {return GetData(args[0], args[1]);}
518         // method4 GetDataHere - not implemented
519
public int method5(int[] args) {return QueryGetData(args[0]);}
520         // method6 GetCanonicalFormatEtc - not implemented
521
// method7 SetData - not implemented
522
public int method8(int[] args) {return EnumFormatEtc(args[0], args[1]);}
523         // method9 DAdvise - not implemented
524
// method10 DUnadvise - not implemented
525
// method11 EnumDAdvise - not implemented
526
};
527 }
528 private void disposeCOMInterfaces() {
529     if (iDataObject != null)
530         iDataObject.dispose();
531     iDataObject = null;
532 }
533 /*
534  * EnumFormatEtc([in] dwDirection, [out] ppenumFormatetc)
535  * Ownership of ppenumFormatetc transfers from callee to caller so reference count on ppenumFormatetc
536  * must be incremented before returning. Caller is responsible for releasing ppenumFormatetc.
537  */

538 private int EnumFormatEtc(int dwDirection, int ppenumFormatetc) {
539     // only allow getting of data - SetData is not currently supported
540
if (dwDirection == COM.DATADIR_SET) return COM.E_NOTIMPL;
541     // what types have been registered?
542
TransferData[] allowedDataTypes = new TransferData[0];
543     for (int i = 0; i < transferAgents.length; i++){
544         TransferData[] formats = transferAgents[i].getSupportedTypes();
545         TransferData[] newAllowedDataTypes = new TransferData[allowedDataTypes.length + formats.length];
546         System.arraycopy(allowedDataTypes, 0, newAllowedDataTypes, 0, allowedDataTypes.length);
547         System.arraycopy(formats, 0, newAllowedDataTypes, allowedDataTypes.length, formats.length);
548         allowedDataTypes = newAllowedDataTypes;
549     }
550     OleEnumFORMATETC enumFORMATETC = new OleEnumFORMATETC();
551     enumFORMATETC.AddRef();
552     FORMATETC[] formats = new FORMATETC[allowedDataTypes.length + 1];
553     for (int i = 0; i < allowedDataTypes.length; i++){
554         formats[i] = allowedDataTypes[i].formatetc;
555     }
556     // include the drop effect format to specify a copy operation
557
FORMATETC dropeffect = new FORMATETC();
558     dropeffect.cfFormat = CFSTR_PREFERREDDROPEFFECT;
559     dropeffect.dwAspect = COM.DVASPECT_CONTENT;
560     dropeffect.lindex = -1;
561     dropeffect.tymed = COM.TYMED_HGLOBAL;
562     formats[formats.length -1] = dropeffect;
563     enumFORMATETC.setFormats(formats);
564     OS.MoveMemory(ppenumFormatetc, new int[] {enumFORMATETC.getAddress()}, 4);
565     return COM.S_OK;
566 }
567 private int GetData(int pFormatetc, int pmedium) {
568     /* Called by a data consumer to obtain data from a source data object.
569        The GetData method renders the data described in the specified FORMATETC
570        structure and transfers it through the specified STGMEDIUM structure.
571        The caller then assumes responsibility for releasing the STGMEDIUM structure.
572     */

573     if (pFormatetc == 0 || pmedium == 0) return COM.E_INVALIDARG;
574     if (QueryGetData(pFormatetc) != COM.S_OK) return COM.DV_E_FORMATETC;
575
576     TransferData transferData = new TransferData();
577     transferData.formatetc = new FORMATETC();
578     COM.MoveMemory(transferData.formatetc, pFormatetc, FORMATETC.sizeof);
579     transferData.type = transferData.formatetc.cfFormat;
580     transferData.stgmedium = new STGMEDIUM();
581     transferData.result = COM.E_FAIL;
582
583     if (transferData.type == CFSTR_PREFERREDDROPEFFECT) {
584         // specify that a copy operation is to be performed
585
STGMEDIUM stgmedium = new STGMEDIUM();
586         stgmedium.tymed = COM.TYMED_HGLOBAL;
587         stgmedium.unionField = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, 4);
588         OS.MoveMemory(stgmedium.unionField, new int[] {COM.DROPEFFECT_COPY}, 4);
589         stgmedium.pUnkForRelease = 0;
590         COM.MoveMemory(pmedium, stgmedium, STGMEDIUM.sizeof);
591         return COM.S_OK;
592     }
593         
594     // get matching transfer agent to perform conversion
595
int transferIndex = -1;
596     for (int i = 0; i < transferAgents.length; i++){
597         if (transferAgents[i].isSupportedType(transferData)){
598             transferIndex = i;
599             break;
600         }
601     }
602     if (transferIndex == -1) return COM.DV_E_FORMATETC;
603     transferAgents[transferIndex].javaToNative(data[transferIndex], transferData);
604     COM.MoveMemory(pmedium, transferData.stgmedium, STGMEDIUM.sizeof);
605     return transferData.result;
606 }
607
608 private int QueryGetData(int pFormatetc) {
609     if (transferAgents == null) return COM.E_FAIL;
610     TransferData transferData = new TransferData();
611     transferData.formatetc = new FORMATETC();
612     COM.MoveMemory(transferData.formatetc, pFormatetc, FORMATETC.sizeof);
613     transferData.type = transferData.formatetc.cfFormat;
614     if (transferData.type == CFSTR_PREFERREDDROPEFFECT) return COM.S_OK;
615     // is this type supported by the transfer agent?
616
for (int i = 0; i < transferAgents.length; i++){
617         if (transferAgents[i].isSupportedType(transferData))
618             return COM.S_OK;
619     }
620     
621     return COM.DV_E_FORMATETC;
622 }
623 /* QueryInterface([in] iid, [out] ppvObject)
624  * Ownership of ppvObject transfers from callee to caller so reference count on ppvObject
625  * must be incremented before returning. Caller is responsible for releasing ppvObject.
626  */

627 private int QueryInterface(int riid, int ppvObject) {
628     if (riid == 0 || ppvObject == 0) return COM.E_INVALIDARG;
629     GUID guid = new GUID();
630     COM.MoveMemory(guid, riid, GUID.sizeof);
631     if (COM.IsEqualGUID(guid, COM.IIDIUnknown) || COM.IsEqualGUID(guid, COM.IIDIDataObject) ) {
632         OS.MoveMemory(ppvObject, new int[] {iDataObject.getAddress()}, 4);
633         AddRef();
634         return COM.S_OK;
635     }
636     OS.MoveMemory(ppvObject, new int[] {0}, 4);
637     return COM.E_NOINTERFACE;
638 }
639 private int Release() {
640     refCount--;
641     if (refCount == 0) {
642         this.data = new Object JavaDoc[0];
643         this.transferAgents = new Transfer[0];
644         disposeCOMInterfaces();
645         COM.CoFreeUnusedLibraries();
646     }
647     return refCount;
648 }
649
650 /**
651  * Returns an array of the data types currently available on the system
652  * clipboard. Use with Transfer.isSupportedType.
653  *
654  * @return array of data types currently available on the system clipboard
655  *
656  * @exception SWTException <ul>
657  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
658  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
659  * </ul>
660  *
661  * @see Transfer#isSupportedType
662  *
663  * @since 3.0
664  */

665 public TransferData[] getAvailableTypes() {
666     return getAvailableTypes(DND.CLIPBOARD);
667 }
668
669 /**
670  * Returns an array of the data types currently available on the specified
671  * clipboard. Use with Transfer.isSupportedType.
672  *
673  * <p>The clipboards value is either one of the clipboard constants defined in
674  * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
675  * (that is, using the <code>int</code> "|" operator) two or more
676  * of those <code>DND</code> clipboard constants.</p>
677  *
678  * @param clipboards from which to get the data types
679  * @return array of data types currently available on the specified clipboard
680  *
681  * @exception SWTException <ul>
682  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
683  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
684  * </ul>
685  *
686  * @see Transfer#isSupportedType
687  * @see DND#CLIPBOARD
688  * @see DND#SELECTION_CLIPBOARD
689  *
690  * @since 3.1
691  */

692 public TransferData[] getAvailableTypes(int clipboards) {
693     checkWidget();
694     if ((clipboards & DND.CLIPBOARD) == 0) return new TransferData[0];
695     FORMATETC[] types = _getAvailableTypes();
696     TransferData[] data = new TransferData[types.length];
697     for (int i = 0; i < types.length; i++) {
698         data[i] = new TransferData();
699         data[i].type = types[i].cfFormat;
700         data[i].formatetc = types[i];
701     }
702     return data;
703 }
704
705 /**
706  * Returns a platform specific list of the data types currently available on the
707  * system clipboard.
708  *
709  * <p>Note: <code>getAvailableTypeNames</code> is a utility for writing a Transfer
710  * sub-class. It should NOT be used within an application because it provides
711  * platform specific information.</p>
712  *
713  * @return a platform specific list of the data types currently available on the
714  * system clipboard
715  *
716  * @exception SWTException <ul>
717  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
718  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
719  * </ul>
720  */

721 public String JavaDoc[] getAvailableTypeNames() {
722     checkWidget();
723     FORMATETC[] types = _getAvailableTypes();
724     String JavaDoc[] names = new String JavaDoc[types.length];
725     int maxSize = 128;
726     for (int i = 0; i < types.length; i++){
727         TCHAR buffer = new TCHAR(0, maxSize);
728         int size = OS.GetClipboardFormatName(types[i].cfFormat, buffer, maxSize);
729         if (size != 0) {
730             names[i] = buffer.toString(0, size);
731         } else {
732             switch (types[i].cfFormat) {
733                 case COM.CF_HDROP: names[i] = "CF_HDROP"; break; //$NON-NLS-1$
734
case COM.CF_TEXT: names[i] = "CF_TEXT"; break; //$NON-NLS-1$
735
case COM.CF_BITMAP: names[i] = "CF_BITMAP"; break; //$NON-NLS-1$
736
case COM.CF_METAFILEPICT: names[i] = "CF_METAFILEPICT"; break; //$NON-NLS-1$
737
case COM.CF_SYLK: names[i] = "CF_SYLK"; break; //$NON-NLS-1$
738
case COM.CF_DIF: names[i] = "CF_DIF"; break; //$NON-NLS-1$
739
case COM.CF_TIFF: names[i] = "CF_TIFF"; break; //$NON-NLS-1$
740
case COM.CF_OEMTEXT: names[i] = "CF_OEMTEXT"; break; //$NON-NLS-1$
741
case COM.CF_DIB: names[i] = "CF_DIB"; break; //$NON-NLS-1$
742
case COM.CF_PALETTE: names[i] = "CF_PALETTE"; break; //$NON-NLS-1$
743
case COM.CF_PENDATA: names[i] = "CF_PENDATA"; break; //$NON-NLS-1$
744
case COM.CF_RIFF: names[i] = "CF_RIFF"; break; //$NON-NLS-1$
745
case COM.CF_WAVE: names[i] = "CF_WAVE"; break; //$NON-NLS-1$
746
case COM.CF_UNICODETEXT: names[i] = "CF_UNICODETEXT"; break; //$NON-NLS-1$
747
case COM.CF_ENHMETAFILE: names[i] = "CF_ENHMETAFILE"; break; //$NON-NLS-1$
748
case COM.CF_LOCALE: names[i] = "CF_LOCALE"; break; //$NON-NLS-1$
749
case COM.CF_MAX: names[i] = "CF_MAX"; break; //$NON-NLS-1$
750
default: names[i] = "UNKNOWN"; //$NON-NLS-1$
751
}
752         }
753     }
754     return names;
755 }
756
757 private FORMATETC[] _getAvailableTypes() {
758     FORMATETC[] types = new FORMATETC[0];
759     int[] ppv = new int[1];
760     /* OleGetClipboard([out] ppDataObject).
761      * AddRef has already been called on ppDataObject by the callee and must be released by the caller.
762      */

763     if (COM.OleGetClipboard(ppv) != COM.S_OK) return types;
764     IDataObject dataObject = new IDataObject(ppv[0]);
765     int[] ppFormatetc = new int[1];
766     /* EnumFormatEtc([in] dwDirection, [out] ppenumFormatetc)
767      * AddRef has already been called on ppenumFormatetc by the callee and must be released by the caller.
768      */

769     int rc = dataObject.EnumFormatEtc(COM.DATADIR_GET, ppFormatetc);
770     dataObject.Release();
771     if (rc != COM.S_OK)return types;
772     IEnumFORMATETC enumFormatetc = new IEnumFORMATETC(ppFormatetc[0]);
773     // Loop over enumerator and save any types that match what we are looking for
774
int rgelt = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, FORMATETC.sizeof);
775     int[] pceltFetched = new int[1];
776     enumFormatetc.Reset();
777     while (enumFormatetc.Next(1, rgelt, pceltFetched) == COM.S_OK && pceltFetched[0] == 1) {
778         FORMATETC formatetc = new FORMATETC();
779         COM.MoveMemory(formatetc, rgelt, FORMATETC.sizeof);
780         FORMATETC[] newTypes = new FORMATETC[types.length + 1];
781         System.arraycopy(types, 0, newTypes, 0, types.length);
782         newTypes[types.length] = formatetc;
783         types = newTypes;
784     }
785     OS.GlobalFree(rgelt);
786     enumFormatetc.Release();
787     return types;
788 }
789 }
790
Popular Tags