KickJava   Java API By Example, From Geeks To Geeks.

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


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.graphics.*;
16 import org.eclipse.swt.widgets.*;
17 import org.eclipse.swt.internal.*;
18 import org.eclipse.swt.internal.ole.win32.*;
19 import org.eclipse.swt.internal.win32.*;
20
21 /**
22  *
23  * <code>DragSource</code> defines the source object for a drag and drop transfer.
24  *
25  * <p>IMPORTANT: This class is <em>not</em> intended to be subclassed.</p>
26  *
27  * <p>A drag source is the object which originates a drag and drop operation. For the specified widget,
28  * it defines the type of data that is available for dragging and the set of operations that can
29  * be performed on that data. The operations can be any bit-wise combination of DND.MOVE, DND.COPY or
30  * DND.LINK. The type of data that can be transferred is specified by subclasses of Transfer such as
31  * TextTransfer or FileTransfer. The type of data transferred can be a predefined system type or it
32  * can be a type defined by the application. For instructions on how to define your own transfer type,
33  * refer to <code>ByteArrayTransfer</code>.</p>
34  *
35  * <p>You may have several DragSources in an application but you can only have one DragSource
36  * per Control. Data dragged from this DragSource can be dropped on a site within this application
37  * or it can be dropped on another application such as an external Text editor.</p>
38  *
39  * <p>The application supplies the content of the data being transferred by implementing the
40  * <code>DragSourceListener</code> and associating it with the DragSource via DragSource#addDragListener.</p>
41  *
42  * <p>When a successful move operation occurs, the application is required to take the appropriate
43  * action to remove the data from its display and remove any associated operating system resources or
44  * internal references. Typically in a move operation, the drop target makes a copy of the data
45  * and the drag source deletes the original. However, sometimes copying the data can take a long
46  * time (such as copying a large file). Therefore, on some platforms, the drop target may actually
47  * move the data in the operating system rather than make a copy. This is usually only done in
48  * file transfers. In this case, the drag source is informed in the DragEnd event that a
49  * DROP_TARGET_MOVE was performed. It is the responsibility of the drag source at this point to clean
50  * up its displayed information. No action needs to be taken on the operating system resources.</p>
51  *
52  * <p> The following example shows a Label widget that allows text to be dragged from it.</p>
53  *
54  * <code><pre>
55  * // Enable a label as a Drag Source
56  * Label label = new Label(shell, SWT.NONE);
57  * // This example will allow text to be dragged
58  * Transfer[] types = new Transfer[] {TextTransfer.getInstance()};
59  * // This example will allow the text to be copied or moved to the drop target
60  * int operations = DND.DROP_MOVE | DND.DROP_COPY;
61  *
62  * DragSource source = new DragSource(label, operations);
63  * source.setTransfer(types);
64  * source.addDragListener(new DragSourceListener() {
65  * public void dragStart(DragSourceEvent e) {
66  * // Only start the drag if there is actually text in the
67  * // label - this text will be what is dropped on the target.
68  * if (label.getText().length() == 0) {
69  * event.doit = false;
70  * }
71  * };
72  * public void dragSetData(DragSourceEvent event) {
73  * // A drop has been performed, so provide the data of the
74  * // requested type.
75  * // (Checking the type of the requested data is only
76  * // necessary if the drag source supports more than
77  * // one data type but is shown here as an example).
78  * if (TextTransfer.getInstance().isSupportedType(event.dataType)){
79  * event.data = label.getText();
80  * }
81  * }
82  * public void dragFinished(DragSourceEvent event) {
83  * // A Move operation has been performed so remove the data
84  * // from the source
85  * if (event.detail == DND.DROP_MOVE)
86  * label.setText("");
87  * }
88  * });
89  * </pre></code>
90  *
91  *
92  * <dl>
93  * <dt><b>Styles</b></dt> <dd>DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK</dd>
94  * <dt><b>Events</b></dt> <dd>DND.DragStart, DND.DragSetData, DND.DragEnd</dd>
95  * </dl>
96  */

97 public class DragSource extends Widget {
98
99     // info for registering as a drag source
100
Control control;
101     Listener controlListener;
102     Transfer[] transferAgents = new Transfer[0];
103     DragSourceEffect dragEffect;
104     Composite topControl;
105     int hwndDrag;
106     
107     // ole interfaces
108
COMObject iDropSource;
109     COMObject iDataObject;
110     int refCount;
111     
112     //workaround - track the operation performed by the drop target for DragEnd event
113
int dataEffect = DND.DROP_NONE;
114     
115     static final String JavaDoc DEFAULT_DRAG_SOURCE_EFFECT = "DEFAULT_DRAG_SOURCE_EFFECT"; //$NON-NLS-1$
116
static final String JavaDoc DRAGSOURCEID = "DragSource"; //$NON-NLS-1$
117
static final int CFSTR_PERFORMEDDROPEFFECT = Transfer.registerType("Performed DropEffect"); //$NON-NLS-1$
118
static final TCHAR WindowClass = new TCHAR (0, "#32770", true);
119
120 /**
121  * Creates a new <code>DragSource</code> to handle dragging from the specified <code>Control</code>.
122  * Creating an instance of a DragSource may cause system resources to be allocated depending on the platform.
123  * It is therefore mandatory that the DragSource instance be disposed when no longer required.
124  *
125  * @param control the <code>Control</code> that the user clicks on to initiate the drag
126  * @param style the bitwise OR'ing of allowed operations; this may be a combination of any of
127  * DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK
128  *
129  * @exception SWTException <ul>
130  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
131  * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
132  * </ul>
133  * @exception SWTError <ul>
134  * <li>ERROR_CANNOT_INIT_DRAG - unable to initiate drag source; this will occur if more than one
135  * drag source is created for a control or if the operating system will not allow the creation
136  * of the drag source</li>
137  * </ul>
138  *
139  * <p>NOTE: ERROR_CANNOT_INIT_DRAG should be an SWTException, since it is a
140  * recoverable error, but can not be changed due to backward compatibility.</p>
141  *
142  * @see Widget#dispose
143  * @see DragSource#checkSubclass
144  * @see DND#DROP_NONE
145  * @see DND#DROP_COPY
146  * @see DND#DROP_MOVE
147  * @see DND#DROP_LINK
148  */

149 public DragSource(Control control, int style) {
150     super(control, checkStyle(style));
151     this.control = control;
152     if (control.getData(DRAGSOURCEID) != null) {
153         DND.error(DND.ERROR_CANNOT_INIT_DRAG);
154     }
155     control.setData(DRAGSOURCEID, this);
156     createCOMInterfaces();
157     this.AddRef();
158
159     controlListener = new Listener() {
160         public void handleEvent(Event event) {
161             if (event.type == SWT.Dispose) {
162                 if (!DragSource.this.isDisposed()) {
163                     DragSource.this.dispose();
164                 }
165             }
166             if (event.type == SWT.DragDetect) {
167                 if (!DragSource.this.isDisposed()) {
168                     DragSource.this.drag(event);
169                 }
170             }
171         }
172     };
173     control.addListener(SWT.Dispose, controlListener);
174     control.addListener(SWT.DragDetect, controlListener);
175     
176     this.addListener(SWT.Dispose, new Listener() {
177         public void handleEvent(Event e) {
178             DragSource.this.onDispose();
179         }
180     });
181
182     Object JavaDoc effect = control.getData(DEFAULT_DRAG_SOURCE_EFFECT);
183     if (effect instanceof DragSourceEffect) {
184         dragEffect = (DragSourceEffect) effect;
185     } else if (control instanceof Tree) {
186         dragEffect = new TreeDragSourceEffect((Tree) control);
187     } else if (control instanceof Table) {
188         dragEffect = new TableDragSourceEffect((Table) control);
189     }
190 }
191
192 static int checkStyle(int style) {
193     if (style == SWT.NONE) return DND.DROP_MOVE;
194     return style;
195 }
196
197 /**
198  * Adds the listener to the collection of listeners who will
199  * be notified when a drag and drop operation is in progress, by sending
200  * it one of the messages defined in the <code>DragSourceListener</code>
201  * interface.
202  *
203  * <p><ul>
204  * <li><code>dragStart</code> is called when the user has begun the actions required to drag the widget.
205  * This event gives the application the chance to decide if a drag should be started.
206  * <li><code>dragSetData</code> is called when the data is required from the drag source.
207  * <li><code>dragFinished</code> is called when the drop has successfully completed (mouse up
208  * over a valid target) or has been terminated (such as hitting the ESC key). Perform cleanup
209  * such as removing data from the source side on a successful move operation.
210  * </ul></p>
211  *
212  * @param listener the listener which should be notified
213  *
214  * @exception IllegalArgumentException <ul>
215  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
216  * </ul>
217  * @exception SWTException <ul>
218  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
219  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
220  * </ul>
221  *
222  * @see DragSourceListener
223  * @see #removeDragListener
224  * @see DragSourceEvent
225  */

226 public void addDragListener(DragSourceListener listener) {
227     if (listener == null) DND.error(SWT.ERROR_NULL_ARGUMENT);
228     DNDListener typedListener = new DNDListener(listener);
229     typedListener.dndWidget = this;
230     addListener(DND.DragStart, typedListener);
231     addListener(DND.DragSetData, typedListener);
232     addListener(DND.DragEnd, typedListener);
233 }
234
235 private int AddRef() {
236     refCount++;
237     return refCount;
238 }
239
240 private void createCOMInterfaces() {
241     // register each of the interfaces that this object implements
242
iDropSource = new COMObject(new int[]{2, 0, 0, 2, 1}){
243         public int method0(int[] args) {return QueryInterface(args[0], args[1]);}
244         public int method1(int[] args) {return AddRef();}
245         public int method2(int[] args) {return Release();}
246         public int method3(int[] args) {return QueryContinueDrag(args[0], args[1]);}
247         public int method4(int[] args) {return GiveFeedback(args[0]);}
248     };
249     
250     iDataObject = new COMObject(new int[]{2, 0, 0, 2, 2, 1, 2, 3, 2, 4, 1, 1}){
251         public int method0(int[] args) {return QueryInterface(args[0], args[1]);}
252         public int method1(int[] args) {return AddRef();}
253         public int method2(int[] args) {return Release();}
254         public int method3(int[] args) {return GetData(args[0], args[1]);}
255         // method4 GetDataHere - not implemented
256
public int method5(int[] args) {return QueryGetData(args[0]);}
257         // method6 GetCanonicalFormatEtc - not implemented
258
public int method7(int[] args) {return SetData(args[0], args[1], args[2]);}
259         public int method8(int[] args) {return EnumFormatEtc(args[0], args[1]);}
260         // method9 DAdvise - not implemented
261
// method10 DUnadvise - not implemented
262
// method11 EnumDAdvise - not implemented
263
};
264 }
265
266 protected void checkSubclass() {
267     String JavaDoc name = getClass().getName();
268     String JavaDoc validName = DragSource.class.getName();
269     if (!validName.equals(name)) {
270         DND.error(SWT.ERROR_INVALID_SUBCLASS);
271     }
272 }
273
274 private void disposeCOMInterfaces() {
275     if (iDropSource != null)
276         iDropSource.dispose();
277     iDropSource = null;
278
279     if (iDataObject != null)
280         iDataObject.dispose();
281     iDataObject = null;
282 }
283
284 private void drag(Event dragEvent) {
285     DNDEvent event = new DNDEvent();
286     event.widget = this;
287     event.x = dragEvent.x;
288     event.y = dragEvent.y;
289     event.time = OS.GetMessageTime();
290     event.doit = true;
291     notifyListeners(DND.DragStart,event);
292     if (!event.doit || transferAgents == null || transferAgents.length == 0 ) return;
293     
294     int[] pdwEffect = new int[1];
295     int operations = opToOs(getStyle());
296     Display display = control.getDisplay();
297     String JavaDoc key = "org.eclipse.swt.internal.win32.runMessagesInIdle"; //$NON-NLS-1$
298
Object JavaDoc oldValue = display.getData(key);
299     display.setData(key, new Boolean JavaDoc(true));
300     ImageList imagelist = null;
301     Image image = event.image;
302     hwndDrag = 0;
303     topControl = null;
304     if (image != null) {
305         imagelist = new ImageList(SWT.NONE);
306         imagelist.add(image);
307         topControl = control.getShell();
308         /*
309          * Bug in Windows. The image is inverted if the shell is RIGHT_TO_LEFT.
310          * The fix is to create a transparent window that covers the shell client
311          * area and use it during the drag to prevent the image from being inverted.
312          * On XP if the shell is RTL, the image is not displayed.
313          */

314         int offset = 0;
315         hwndDrag = topControl.handle;
316         if ((topControl.getStyle() & SWT.RIGHT_TO_LEFT) != 0) {
317             offset = image.getBounds().width;
318             RECT rect = new RECT ();
319             OS.GetClientRect (topControl.handle, rect);
320             hwndDrag = OS.CreateWindowEx (
321                 OS.WS_EX_TRANSPARENT | OS.WS_EX_NOINHERITLAYOUT,
322                 WindowClass,
323                 null,
324                 OS.WS_CHILD | OS.WS_CLIPSIBLINGS,
325                 0, 0,
326                 rect.right - rect.left, rect.bottom - rect.top,
327                 topControl.handle,
328                 0,
329                 OS.GetModuleHandle (null),
330                 null);
331             OS.ShowWindow (hwndDrag, OS.SW_SHOW);
332         }
333         OS.ImageList_BeginDrag(imagelist.getHandle(), 0, offset, 0);
334         /*
335         * Feature in Windows. When ImageList_DragEnter() is called,
336         * it takes a snapshot of the screen If a drag is started
337         * when another window is in front, then the snapshot will
338         * contain part of the other window, causing pixel corruption.
339         * The fix is to force all paints to be delivered before
340         * calling ImageList_DragEnter().
341         */

342         if (OS.IsWinCE) {
343             OS.UpdateWindow (topControl.handle);
344         } else {
345             int flags = OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN;
346             OS.RedrawWindow (topControl.handle, null, 0, flags);
347         }
348         POINT pt = new POINT ();
349         pt.x = dragEvent.x;
350         pt.y = dragEvent.y;
351         OS.MapWindowPoints (control.handle, 0, pt, 1);
352         RECT rect = new RECT ();
353         OS.GetWindowRect (hwndDrag, rect);
354         OS.ImageList_DragEnter(hwndDrag, pt.x - rect.left, pt.y - rect.top);
355     }
356     int result = COM.DRAGDROP_S_CANCEL;
357     try {
358         result = COM.DoDragDrop(iDataObject.getAddress(), iDropSource.getAddress(), operations, pdwEffect);
359     } finally {
360         // ensure that we don't leave transparent window around
361
if (hwndDrag != 0) {
362             OS.ImageList_DragLeave(hwndDrag);
363             OS.ImageList_EndDrag();
364             imagelist.dispose();
365             if (hwndDrag != topControl.handle) OS.DestroyWindow(hwndDrag);
366             hwndDrag = 0;
367             topControl = null;
368         }
369         display.setData(key, oldValue);
370     }
371     int operation = osToOp(pdwEffect[0]);
372     if (dataEffect == DND.DROP_MOVE) {
373         operation = (operation == DND.DROP_NONE || operation == DND.DROP_COPY) ? DND.DROP_TARGET_MOVE : DND.DROP_MOVE;
374     } else {
375         if (dataEffect != DND.DROP_NONE) {
376             operation = dataEffect;
377         }
378     }
379     event = new DNDEvent();
380     event.widget = this;
381     event.time = OS.GetMessageTime();
382     event.doit = (result == COM.DRAGDROP_S_DROP);
383     event.detail = operation;
384     notifyListeners(DND.DragEnd,event);
385     dataEffect = DND.DROP_NONE;
386 }
387 /*
388  * EnumFormatEtc([in] dwDirection, [out] ppenumFormatetc)
389  * Ownership of ppenumFormatetc transfers from callee to caller so reference count on ppenumFormatetc
390  * must be incremented before returning. Caller is responsible for releasing ppenumFormatetc.
391  */

392 private int EnumFormatEtc(int dwDirection, int ppenumFormatetc) {
393     // only allow getting of data - SetData is not currently supported
394
if (dwDirection == COM.DATADIR_SET) return COM.E_NOTIMPL;
395
396     // what types have been registered?
397
TransferData[] allowedDataTypes = new TransferData[0];
398     for (int i = 0; i < transferAgents.length; i++){
399         Transfer transferAgent = transferAgents[i];
400         if (transferAgent != null) {
401             TransferData[] formats = transferAgent.getSupportedTypes();
402             TransferData[] newAllowedDataTypes = new TransferData[allowedDataTypes.length + formats.length];
403             System.arraycopy(allowedDataTypes, 0, newAllowedDataTypes, 0, allowedDataTypes.length);
404             System.arraycopy(formats, 0, newAllowedDataTypes, allowedDataTypes.length, formats.length);
405             allowedDataTypes = newAllowedDataTypes;
406         }
407     }
408     
409     OleEnumFORMATETC enumFORMATETC = new OleEnumFORMATETC();
410     enumFORMATETC.AddRef();
411     
412     FORMATETC[] formats = new FORMATETC[allowedDataTypes.length];
413     for (int i = 0; i < formats.length; i++){
414         formats[i] = allowedDataTypes[i].formatetc;
415     }
416     enumFORMATETC.setFormats(formats);
417     
418     OS.MoveMemory(ppenumFormatetc, new int[] {enumFORMATETC.getAddress()}, 4);
419     return COM.S_OK;
420 }
421 /**
422  * Returns the Control which is registered for this DragSource. This is the control that the
423  * user clicks in to initiate dragging.
424  *
425  * @return the Control which is registered for this DragSource
426  */

427 public Control getControl() {
428     return control;
429 }
430
431 private int GetData(int pFormatetc, int pmedium) {
432     /* Called by a data consumer to obtain data from a source data object.
433        The GetData method renders the data described in the specified FORMATETC
434        structure and transfers it through the specified STGMEDIUM structure.
435        The caller then assumes responsibility for releasing the STGMEDIUM structure.
436     */

437     if (pFormatetc == 0 || pmedium == 0) return COM.E_INVALIDARG;
438
439     if (QueryGetData(pFormatetc) != COM.S_OK) return COM.DV_E_FORMATETC;
440
441     TransferData transferData = new TransferData();
442     transferData.formatetc = new FORMATETC();
443     COM.MoveMemory(transferData.formatetc, pFormatetc, FORMATETC.sizeof);
444     transferData.type = transferData.formatetc.cfFormat;
445     transferData.stgmedium = new STGMEDIUM();
446     transferData.result = COM.E_FAIL;
447     
448     DNDEvent event = new DNDEvent();
449     event.widget = this;
450     event.time = OS.GetMessageTime();
451     event.dataType = transferData;
452     notifyListeners(DND.DragSetData,event);
453     
454     // get matching transfer agent to perform conversion
455
Transfer transfer = null;
456     for (int i = 0; i < transferAgents.length; i++){
457         Transfer transferAgent = transferAgents[i];
458         if (transferAgent != null && transferAgent.isSupportedType(transferData)){
459             transfer = transferAgent;
460             break;
461         }
462     }
463     
464     if (transfer == null) return COM.DV_E_FORMATETC;
465     transfer.javaToNative(event.data, transferData);
466     if (transferData.result != COM.S_OK) return transferData.result;
467     COM.MoveMemory(pmedium, transferData.stgmedium, STGMEDIUM.sizeof);
468     return transferData.result;
469 }
470
471 /**
472  * Returns the drag effect that is registered for this DragSource. This drag
473  * effect will be used during a drag and drop operation.
474  *
475  * @return the drag effect that is registered for this DragSource
476  *
477  * @since 3.3
478  */

479 public DragSourceEffect getDragSourceEffect() {
480     return dragEffect;
481 }
482
483 /**
484  * Returns the list of data types that can be transferred by this DragSource.
485  *
486  * @return the list of data types that can be transferred by this DragSource
487  */

488 public Transfer[] getTransfer(){
489     return transferAgents;
490 }
491
492 private int GiveFeedback(int dwEffect) {
493     return COM.DRAGDROP_S_USEDEFAULTCURSORS;
494 }
495
496 private int QueryContinueDrag(int fEscapePressed, int grfKeyState) {
497     if (topControl != null && topControl.isDisposed()) return COM.DRAGDROP_S_CANCEL;
498     if (fEscapePressed != 0){
499         if (hwndDrag != 0) OS.ImageList_DragLeave(hwndDrag);
500         return COM.DRAGDROP_S_CANCEL;
501     }
502     /*
503     * Bug in Windows. On some machines that do not have XBUTTONs,
504     * the MK_XBUTTON1 and OS.MK_XBUTTON2 bits are sometimes set,
505     * causing mouse capture to become stuck. The fix is to test
506     * for the extra buttons only when they exist.
507     */

508     int mask = OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON;
509 // if (display.xMouse) mask |= OS.MK_XBUTTON1 | OS.MK_XBUTTON2;
510
if ((grfKeyState & mask) == 0) {
511         if (hwndDrag != 0) OS.ImageList_DragLeave(hwndDrag);
512         return COM.DRAGDROP_S_DROP;
513     }
514     
515     if (hwndDrag != 0) {
516         POINT pt = new POINT ();
517         OS.GetCursorPos (pt);
518         RECT rect = new RECT ();
519         OS.GetWindowRect (hwndDrag, rect);
520         OS.ImageList_DragMove (pt.x - rect.left, pt.y - rect.top);
521     }
522     return COM.S_OK;
523 }
524
525 private void onDispose() {
526     if (control == null) return;
527     this.Release();
528     if (controlListener != null){
529         control.removeListener(SWT.Dispose, controlListener);
530         control.removeListener(SWT.DragDetect, controlListener);
531     }
532     controlListener = null;
533     control.setData(DRAGSOURCEID, null);
534     control = null;
535     transferAgents = null;
536 }
537
538 private int opToOs(int operation) {
539     int osOperation = 0;
540     if ((operation & DND.DROP_COPY) != 0){
541         osOperation |= COM.DROPEFFECT_COPY;
542     }
543     if ((operation & DND.DROP_LINK) != 0) {
544         osOperation |= COM.DROPEFFECT_LINK;
545     }
546     if ((operation & DND.DROP_MOVE) != 0) {
547         osOperation |= COM.DROPEFFECT_MOVE;
548     }
549     return osOperation;
550 }
551
552 private int osToOp(int osOperation){
553     int operation = 0;
554     if ((osOperation & COM.DROPEFFECT_COPY) != 0){
555         operation |= DND.DROP_COPY;
556     }
557     if ((osOperation & COM.DROPEFFECT_LINK) != 0) {
558         operation |= DND.DROP_LINK;
559     }
560     if ((osOperation & COM.DROPEFFECT_MOVE) != 0) {
561         operation |= DND.DROP_MOVE;
562     }
563     return operation;
564 }
565
566 private int QueryGetData(int pFormatetc) {
567     if (transferAgents == null) return COM.E_FAIL;
568     TransferData transferData = new TransferData();
569     transferData.formatetc = new FORMATETC();
570     COM.MoveMemory(transferData.formatetc, pFormatetc, FORMATETC.sizeof);
571     transferData.type = transferData.formatetc.cfFormat;
572
573     // is this type supported by the transfer agent?
574
for (int i = 0; i < transferAgents.length; i++){
575         Transfer transfer = transferAgents[i];
576         if (transfer != null && transfer.isSupportedType(transferData))
577             return COM.S_OK;
578     }
579     
580     return COM.DV_E_FORMATETC;
581 }
582
583 /* QueryInterface([in] riid, [out] ppvObject)
584  * Ownership of ppvObject transfers from callee to caller so reference count on ppvObject
585  * must be incremented before returning. Caller is responsible for releasing ppvObject.
586  */

587 private int QueryInterface(int riid, int ppvObject) {
588     if (riid == 0 || ppvObject == 0)
589         return COM.E_INVALIDARG;
590     GUID guid = new GUID();
591     COM.MoveMemory(guid, riid, GUID.sizeof);
592     
593     if (COM.IsEqualGUID(guid, COM.IIDIUnknown) || COM.IsEqualGUID(guid, COM.IIDIDropSource)) {
594         OS.MoveMemory(ppvObject, new int[] {iDropSource.getAddress()}, 4);
595         AddRef();
596         return COM.S_OK;
597     }
598
599     if (COM.IsEqualGUID(guid, COM.IIDIDataObject) ) {
600         OS.MoveMemory(ppvObject, new int[] {iDataObject.getAddress()}, 4);
601         AddRef();
602         return COM.S_OK;
603     }
604     
605     OS.MoveMemory(ppvObject, new int[] {0}, 4);
606     return COM.E_NOINTERFACE;
607 }
608
609 private int Release() {
610     refCount--;
611     if (refCount == 0) {
612         disposeCOMInterfaces();
613         COM.CoFreeUnusedLibraries();
614     }
615     return refCount;
616 }
617
618 /**
619  * Removes the listener from the collection of listeners who will
620  * be notified when a drag and drop operation is in progress.
621  *
622  * @param listener the listener which should be notified
623  *
624  * @exception IllegalArgumentException <ul>
625  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
626  * </ul>
627  * @exception SWTException <ul>
628  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
629  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
630  * </ul>
631  *
632  * @see DragSourceListener
633  * @see #addDragListener
634  */

635 public void removeDragListener(DragSourceListener listener) {
636     if (listener == null) DND.error(SWT.ERROR_NULL_ARGUMENT);
637     removeListener(DND.DragStart, listener);
638     removeListener(DND.DragSetData, listener);
639     removeListener(DND.DragEnd, listener);
640 }
641
642 private int SetData(int pFormatetc, int pmedium, int fRelease) {
643     if (pFormatetc == 0 || pmedium == 0) return COM.E_INVALIDARG;
644     FORMATETC formatetc = new FORMATETC();
645     COM.MoveMemory(formatetc, pFormatetc, FORMATETC.sizeof);
646     if (formatetc.cfFormat == CFSTR_PERFORMEDDROPEFFECT && formatetc.tymed == COM.TYMED_HGLOBAL) {
647         STGMEDIUM stgmedium = new STGMEDIUM();
648         COM.MoveMemory(stgmedium, pmedium,STGMEDIUM.sizeof);
649         int[] ptrEffect = new int[1];
650         OS.MoveMemory(ptrEffect, stgmedium.unionField,4);
651         int[] effect = new int[1];
652         OS.MoveMemory(effect, ptrEffect[0],4);
653         dataEffect = osToOp(effect[0]);
654     }
655     if (fRelease == 1) {
656         COM.ReleaseStgMedium(pmedium);
657     }
658     return COM.S_OK;
659 }
660
661 /**
662  * Specifies the drag effect for this DragSource. This drag effect will be
663  * used during a drag and drop operation.
664  *
665  * @param effect the drag effect that is registered for this DragSource
666  *
667  * @since 3.3
668  */

669 public void setDragSourceEffect(DragSourceEffect effect) {
670     dragEffect = effect;
671 }
672
673 /**
674  * Specifies the list of data types that can be transferred by this DragSource.
675  * The application must be able to provide data to match each of these types when
676  * a successful drop has occurred.
677  *
678  * @param transferAgents a list of Transfer objects which define the types of data that can be
679  * dragged from this source
680  */

681 public void setTransfer(Transfer[] transferAgents){
682     this.transferAgents = transferAgents;
683 }
684
685 }
686
Popular Tags