1 /*******************************************************************************
2 * Copyright (c) 2000, 2019 IBM Corporation and others.
4 * This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License 2.0
6 * which accompanies this distribution, and is available at
7 * https://www.eclipse.org/legal/epl-2.0/
9 * SPDX-License-Identifier: EPL-2.0
12 * IBM Corporation - initial API and implementation
13 *******************************************************************************/
14 package org.eclipse.swt.dnd;
16 import org.eclipse.swt.*;
17 import org.eclipse.swt.internal.*;
18 import org.eclipse.swt.internal.ole.win32.*;
19 import org.eclipse.swt.internal.win32.*;
20 import org.eclipse.swt.widgets.*;
24 * Class <code>DropTarget</code> defines the target object for a drag and drop transfer.
26 * <p>IMPORTANT: This class is <em>not</em> intended to be subclassed.</p>
28 * <p>This class identifies the <code>Control</code> over which the user must position the cursor
29 * in order to drop the data being transferred. It also specifies what data types can be dropped on
30 * this control and what operations can be performed. You may have several DropTragets in an
31 * application but there can only be a one to one mapping between a <code>Control</code> and a <code>DropTarget</code>.
32 * The DropTarget can receive data from within the same application or from other applications
33 * (such as text dragged from a text editor like Word).</p>
36 * int operations = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK;
37 * Transfer[] types = new Transfer[] {TextTransfer.getInstance()};
38 * DropTarget target = new DropTarget(label, operations);
39 * target.setTransfer(types);
42 * <p>The application is notified of data being dragged over this control and of when a drop occurs by
43 * implementing the interface <code>DropTargetListener</code> which uses the class
44 * <code>DropTargetEvent</code>. The application can modify the type of drag being performed
45 * on this Control at any stage of the drag by modifying the <code>event.detail</code> field or the
46 * <code>event.currentDataType</code> field. When the data is dropped, it is the responsibility of
47 * the application to copy this data for its own purposes.
50 * target.addDropListener (new DropTargetListener() {
51 * public void dragEnter(DropTargetEvent event) {};
52 * public void dragOver(DropTargetEvent event) {};
53 * public void dragLeave(DropTargetEvent event) {};
54 * public void dragOperationChanged(DropTargetEvent event) {};
55 * public void dropAccept(DropTargetEvent event) {}
56 * public void drop(DropTargetEvent event) {
57 * // A drop has occurred, copy over the data
58 * if (event.data == null) { // no data to copy, indicate failure in event.detail
59 * event.detail = DND.DROP_NONE;
62 * label.setText ((String) event.data); // data copied to label text
68 * <dt><b>Styles</b></dt> <dd>DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK</dd>
69 * <dt><b>Events</b></dt> <dd>DND.DragEnter, DND.DragLeave, DND.DragOver, DND.DragOperationChanged,
70 * DND.DropAccept, DND.Drop </dd>
73 * @see <a href="http://www.eclipse.org/swt/snippets/#dnd">Drag and Drop snippets</a>
74 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: DNDExample</a>
75 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
76 * @noextend This class is not intended to be subclassed by clients.
78 public class DropTarget extends Widget {
81 Listener controlListener;
82 Transfer[] transferAgents = new Transfer[0];
83 DropTargetEffect dropEffect;
85 // Track application selections
86 TransferData selectedDataType;
87 int selectedOperation;
89 // workaround - There is no event for "operation changed" so track operation based on key state
90 int keyOperation = -1;
92 // workaround - The dataobject address is only passed as an argument in drag enter and drop.
93 // To allow applications to query the data values during the drag over operations,
94 // maintain a reference to it.
95 IDataObject iDataObject;
98 COMObject iDropTarget;
101 static final String DEFAULT_DROP_TARGET_EFFECT = "DEFAULT_DROP_TARGET_EFFECT"; //$NON-NLS-1$
104 * Creates a new <code>DropTarget</code> to allow data to be dropped on the specified
105 * <code>Control</code>.
106 * Creating an instance of a DropTarget may cause system resources to be allocated
107 * depending on the platform. It is therefore mandatory that the DropTarget instance
108 * be disposed when no longer required.
110 * @param control the <code>Control</code> over which the user positions the cursor to drop the data
111 * @param style the bitwise OR'ing of allowed operations; this may be a combination of any of
112 * DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK
114 * @exception SWTException <ul>
115 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
116 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
118 * @exception SWTError <ul>
119 * <li>ERROR_CANNOT_INIT_DROP - unable to initiate drop target; this will occur if more than one
120 * drop target is created for a control or if the operating system will not allow the creation
121 * of the drop target</li>
124 * <p>NOTE: ERROR_CANNOT_INIT_DROP should be an SWTException, since it is a
125 * recoverable error, but can not be changed due to backward compatibility.</p>
127 * @see Widget#dispose
128 * @see DropTarget#checkSubclass
134 public DropTarget(Control control, int style) {
135 super (control, checkStyle(style));
136 this.control = control;
137 if (control.getData(DND.DROP_TARGET_KEY) != null) {
138 DND.error(DND.ERROR_CANNOT_INIT_DROP);
140 control.setData(DND.DROP_TARGET_KEY, this);
141 createCOMInterfaces();
144 if (COM.CoLockObjectExternal(iDropTarget.getAddress(), true, true) != COM.S_OK)
145 DND.error(DND.ERROR_CANNOT_INIT_DROP);
146 if (COM.RegisterDragDrop( control.handle, iDropTarget.getAddress()) != COM.S_OK)
147 DND.error(DND.ERROR_CANNOT_INIT_DROP);
149 controlListener = event -> {
150 if (!DropTarget.this.isDisposed()){
151 DropTarget.this.dispose();
154 control.addListener (SWT.Dispose, controlListener);
156 this.addListener(SWT.Dispose, event -> onDispose());
158 Object effect = control.getData(DEFAULT_DROP_TARGET_EFFECT);
159 if (effect instanceof DropTargetEffect) {
160 dropEffect = (DropTargetEffect) effect;
161 } else if (control instanceof Table) {
162 dropEffect = new TableDropTargetEffect((Table) control);
163 } else if (control instanceof Tree) {
164 dropEffect = new TreeDropTargetEffect((Tree) control);
168 static int checkStyle (int style) {
169 if (style == SWT.NONE) return DND.DROP_MOVE;
174 * Adds the listener to the collection of listeners who will
175 * be notified when a drag and drop operation is in progress, by sending
176 * it one of the messages defined in the <code>DropTargetListener</code>
180 * <li><code>dragEnter</code> is called when the cursor has entered the drop target boundaries
181 * <li><code>dragLeave</code> is called when the cursor has left the drop target boundaries and just before
182 * the drop occurs or is cancelled.
183 * <li><code>dragOperationChanged</code> is called when the operation being performed has changed
184 * (usually due to the user changing the selected modifier key(s) while dragging)
185 * <li><code>dragOver</code> is called when the cursor is moving over the drop target
186 * <li><code>dropAccept</code> is called just before the drop is performed. The drop target is given
187 * the chance to change the nature of the drop or veto the drop by setting the <code>event.detail</code> field
188 * <li><code>drop</code> is called when the data is being dropped
191 * @param listener the listener which should be notified
193 * @exception IllegalArgumentException <ul>
194 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
196 * @exception SWTException <ul>
197 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
198 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
201 * @see DropTargetListener
202 * @see #getDropListeners
203 * @see #removeDropListener
204 * @see DropTargetEvent
206 public void addDropListener(DropTargetListener listener) {
207 if (listener == null) DND.error (SWT.ERROR_NULL_ARGUMENT);
208 DNDListener typedListener = new DNDListener (listener);
209 typedListener.dndWidget = this;
210 addListener (DND.DragEnter, typedListener);
211 addListener (DND.DragLeave, typedListener);
212 addListener (DND.DragOver, typedListener);
213 addListener (DND.DragOperationChanged, typedListener);
214 addListener (DND.Drop, typedListener);
215 addListener (DND.DropAccept, typedListener);
224 protected void checkSubclass () {
225 String name = getClass().getName ();
226 String validName = DropTarget.class.getName();
227 if (!validName.equals(name)) {
228 DND.error (SWT.ERROR_INVALID_SUBCLASS);
232 void createCOMInterfaces() {
233 // register each of the interfaces that this object implements
234 boolean is32 = C.PTR_SIZEOF == 4;
235 iDropTarget = new COMObject(new int[]{2, 0, 0, is32 ? 5 : 4, is32 ? 4 : 3, 0, is32 ? 5 : 4}){
237 public long method0(long[] args) {return QueryInterface(args[0], args[1]);}
239 public long method1(long[] args) {return AddRef();}
241 public long method2(long[] args) {return Release();}
243 public long method3(long[] args) {
244 if (args.length == 5) {
245 return DragEnter(args[0], (int)args[1], (int)args[2], (int)args[3], args[4]);
247 return DragEnter_64(args[0], (int)args[1], args[2], args[3]);
251 public long method4(long[] args) {
252 if (args.length == 4) {
253 return DragOver((int)args[0], (int)args[1], (int)args[2], args[3]);
255 return DragOver_64((int)args[0], args[1], args[2]);
259 public long method5(long[] args) {return DragLeave();}
261 public long method6(long[] args) {
262 if (args.length == 5) {
263 return Drop(args[0], (int)args[1], (int)args[2], (int)args[3], args[4]);
265 return Drop_64(args[0], (int)args[1], args[2], args[3]);
271 void disposeCOMInterfaces() {
272 if (iDropTarget != null)
273 iDropTarget.dispose();
277 int DragEnter_64(long pDataObject, int grfKeyState, long pt, long pdwEffect) {
278 POINT point = new POINT();
279 OS.MoveMemory(point, new long[]{pt}, 8);
280 return DragEnter(pDataObject, grfKeyState, point.x, point.y, pdwEffect);
283 int DragEnter(long pDataObject, int grfKeyState, int pt_x, int pt_y, long pdwEffect) {
284 pt_x = DPIUtil.autoScaleDown(pt_x);// To Points
285 pt_y = DPIUtil.autoScaleDown(pt_y);// To Points
286 selectedDataType = null;
287 selectedOperation = DND.DROP_NONE;
288 if (iDataObject != null) iDataObject.Release();
291 DNDEvent event = new DNDEvent();
292 if (!setEventData(event, pDataObject, grfKeyState, pt_x, pt_y, pdwEffect)) {
293 OS.MoveMemory(pdwEffect, new int[] {COM.DROPEFFECT_NONE}, 4);
297 // Remember the iDataObject because it is not passed into the DragOver callback
298 iDataObject = new IDataObject(pDataObject);
299 iDataObject.AddRef();
301 int allowedOperations = event.operations;
302 TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length];
303 System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length);
304 notifyListeners(DND.DragEnter, event);
306 if (event.detail == DND.DROP_DEFAULT) {
307 event.detail = (allowedOperations & DND.DROP_MOVE) != 0 ? DND.DROP_MOVE : DND.DROP_NONE;
310 selectedDataType = null;
311 for (int i = 0; i < allowedDataTypes.length; i++) {
312 if (TransferData.sameType(allowedDataTypes[i], event.dataType)){
313 selectedDataType = allowedDataTypes[i];
318 selectedOperation = DND.DROP_NONE;
319 if (selectedDataType != null && ((allowedOperations & event.detail) != 0)) {
320 selectedOperation = event.detail;
323 OS.MoveMemory(pdwEffect, new int[] {opToOs(selectedOperation)}, 4);
330 if (iDataObject == null) return COM.S_FALSE;
332 DNDEvent event = new DNDEvent();
334 event.time = OS.GetMessageTime();
335 event.detail = DND.DROP_NONE;
336 notifyListeners(DND.DragLeave, event);
339 iDataObject.Release();
344 int DragOver_64(int grfKeyState, long pt, long pdwEffect) {
345 POINT point = new POINT();
346 OS.MoveMemory(point, new long[]{pt}, 8);
347 return DragOver(grfKeyState, point.x, point.y, pdwEffect);
350 int DragOver(int grfKeyState, int pt_x, int pt_y, long pdwEffect) {
351 pt_x = DPIUtil.autoScaleDown(pt_x);// To Points
352 pt_y = DPIUtil.autoScaleDown(pt_y);// To Points
353 if (iDataObject == null) return COM.S_FALSE;
354 int oldKeyOperation = keyOperation;
356 DNDEvent event = new DNDEvent();
357 if (!setEventData(event, iDataObject.getAddress(), grfKeyState, pt_x, pt_y, pdwEffect)) {
359 OS.MoveMemory(pdwEffect, new int[] {COM.DROPEFFECT_NONE}, 4);
363 int allowedOperations = event.operations;
364 TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length];
365 System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length);
367 if (keyOperation == oldKeyOperation) {
368 event.type = DND.DragOver;
369 event.dataType = selectedDataType;
370 event.detail = selectedOperation;
372 event.type = DND.DragOperationChanged;
373 event.dataType = selectedDataType;
375 notifyListeners(event.type, event);
377 if (event.detail == DND.DROP_DEFAULT) {
378 event.detail = (allowedOperations & DND.DROP_MOVE) != 0 ? DND.DROP_MOVE : DND.DROP_NONE;
381 selectedDataType = null;
382 for (int i = 0; i < allowedDataTypes.length; i++) {
383 if (TransferData.sameType(allowedDataTypes[i], event.dataType)){
384 selectedDataType = allowedDataTypes[i];
389 selectedOperation = DND.DROP_NONE;
390 if (selectedDataType != null && ((allowedOperations & event.detail) == event.detail)) {
391 selectedOperation = event.detail;
394 OS.MoveMemory(pdwEffect, new int[] {opToOs(selectedOperation)}, 4);
398 int Drop_64(long pDataObject, int grfKeyState, long pt, long pdwEffect) {
399 POINT point = new POINT();
400 OS.MoveMemory(point, new long[]{pt}, 8);
401 return Drop(pDataObject, grfKeyState, point.x, point.y, pdwEffect);
404 int Drop(long pDataObject, int grfKeyState, int pt_x, int pt_y, long pdwEffect) {
406 pt_x = DPIUtil.autoScaleDown(pt_x);// To Points
407 pt_y = DPIUtil.autoScaleDown(pt_y);// To Points
408 DNDEvent event = new DNDEvent();
410 event.time = OS.GetMessageTime();
411 if (dropEffect != null) {
412 event.item = dropEffect.getItem(pt_x, pt_y);
414 event.detail = DND.DROP_NONE;
415 notifyListeners(DND.DragLeave, event);
418 event = new DNDEvent();
419 if (!setEventData(event, pDataObject, grfKeyState, pt_x, pt_y, pdwEffect)) {
421 OS.MoveMemory(pdwEffect, new int[] {COM.DROPEFFECT_NONE}, 4);
425 int allowedOperations = event.operations;
426 TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length];
427 System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length);
428 event.dataType = selectedDataType;
429 event.detail = selectedOperation;
430 notifyListeners(DND.DropAccept,event);
433 selectedDataType = null;
434 for (int i = 0; i < allowedDataTypes.length; i++) {
435 if (TransferData.sameType(allowedDataTypes[i], event.dataType)){
436 selectedDataType = allowedDataTypes[i];
440 selectedOperation = DND.DROP_NONE;
441 if (selectedDataType != null && (allowedOperations & event.detail) == event.detail) {
442 selectedOperation = event.detail;
445 if (selectedOperation == DND.DROP_NONE){
446 OS.MoveMemory(pdwEffect, new int[] {COM.DROPEFFECT_NONE}, 4);
450 // Get Data in a Java format
451 Object object = null;
452 for (int i = 0; i < transferAgents.length; i++){
453 Transfer transfer = transferAgents[i];
454 if (transfer != null && transfer.isSupportedType(selectedDataType)){
455 object = transfer.nativeToJava(selectedDataType);
460 selectedOperation = DND.DROP_NONE;
463 event.detail = selectedOperation;
464 event.dataType = selectedDataType;
466 OS.ImageList_DragShowNolock(false);
468 notifyListeners(DND.Drop,event);
470 OS.ImageList_DragShowNolock(true);
473 selectedOperation = DND.DROP_NONE;
474 if ((allowedOperations & event.detail) == event.detail) {
475 selectedOperation = event.detail;
477 //notify source of action taken
478 OS.MoveMemory(pdwEffect, new int[] {opToOs(selectedOperation)}, 4);
481 if (iDataObject != null) {
482 iDataObject.Release();
489 * Returns the Control which is registered for this DropTarget. This is the control over which the
490 * user positions the cursor to drop the data.
492 * @return the Control which is registered for this DropTarget
494 public Control getControl () {
499 * Returns an array of listeners who will be notified when a drag and drop
500 * operation is in progress, by sending it one of the messages defined in
501 * the <code>DropTargetListener</code> interface.
503 * @return the listeners who will be notified when a drag and drop
504 * operation is in progress
506 * @exception SWTException <ul>
507 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
508 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
511 * @see DropTargetListener
512 * @see #addDropListener
513 * @see #removeDropListener
514 * @see DropTargetEvent
518 public DropTargetListener[] getDropListeners() {
519 Listener[] listeners = getListeners(DND.DragEnter);
520 int length = listeners.length;
521 DropTargetListener[] dropListeners = new DropTargetListener[length];
523 for (int i = 0; i < length; i++) {
524 Listener listener = listeners[i];
525 if (listener instanceof DNDListener) {
526 dropListeners[count] = (DropTargetListener) ((DNDListener) listener).getEventListener();
530 if (count == length) return dropListeners;
531 DropTargetListener[] result = new DropTargetListener[count];
532 System.arraycopy(dropListeners, 0, result, 0, count);
537 * Returns the drop effect for this DropTarget. This drop effect will be
538 * used during a drag and drop to display the drag under effect on the
541 * @return the drop effect that is registered for this DropTarget
545 public DropTargetEffect getDropTargetEffect() {
549 int getOperationFromKeyState(int grfKeyState) {
550 boolean ctrl = (grfKeyState & OS.MK_CONTROL) != 0;
551 boolean shift = (grfKeyState & OS.MK_SHIFT) != 0;
552 boolean alt = (grfKeyState & OS.MK_ALT) != 0;
554 if (ctrl || shift) return DND.DROP_DEFAULT;
555 return DND.DROP_LINK;
557 if (ctrl && shift) return DND.DROP_LINK;
558 if (ctrl)return DND.DROP_COPY;
559 if (shift)return DND.DROP_MOVE;
560 return DND.DROP_DEFAULT;
564 * Returns a list of the data types that can be transferred to this DropTarget.
566 * @return a list of the data types that can be transferred to this DropTarget
568 public Transfer[] getTransfer() {
569 return transferAgents;
573 if (control == null) return;
575 COM.RevokeDragDrop(control.handle);
577 if (controlListener != null)
578 control.removeListener(SWT.Dispose, controlListener);
579 controlListener = null;
580 control.setData(DND.DROP_TARGET_KEY, null);
581 transferAgents = null;
584 COM.CoLockObjectExternal(iDropTarget.getAddress(), false, true);
587 if (iDataObject != null) {
588 iDataObject.Release();
592 if (COM.FreeUnusedLibraries) {
593 COM.CoFreeUnusedLibraries();
597 int opToOs(int operation) {
599 if ((operation & DND.DROP_COPY) != 0){
600 osOperation |= COM.DROPEFFECT_COPY;
602 if ((operation & DND.DROP_LINK) != 0) {
603 osOperation |= COM.DROPEFFECT_LINK;
605 if ((operation & DND.DROP_MOVE) != 0) {
606 osOperation |= COM.DROPEFFECT_MOVE;
611 int osToOp(int osOperation){
613 if ((osOperation & COM.DROPEFFECT_COPY) != 0){
614 operation |= DND.DROP_COPY;
616 if ((osOperation & COM.DROPEFFECT_LINK) != 0) {
617 operation |= DND.DROP_LINK;
619 if ((osOperation & COM.DROPEFFECT_MOVE) != 0) {
620 operation |= DND.DROP_MOVE;
625 /* QueryInterface([in] iid, [out] ppvObject)
626 * Ownership of ppvObject transfers from callee to caller so reference count on ppvObject
627 * must be incremented before returning. Caller is responsible for releasing ppvObject.
629 int QueryInterface(long riid, long ppvObject) {
631 if (riid == 0 || ppvObject == 0)
632 return COM.E_INVALIDARG;
633 GUID guid = new GUID();
634 COM.MoveMemory(guid, riid, GUID.sizeof);
635 if (COM.IsEqualGUID(guid, COM.IIDIUnknown) || COM.IsEqualGUID(guid, COM.IIDIDropTarget)) {
636 OS.MoveMemory(ppvObject, new long[] {iDropTarget.getAddress()}, C.PTR_SIZEOF);
641 OS.MoveMemory(ppvObject, new long[] {0}, C.PTR_SIZEOF);
642 return COM.E_NOINTERFACE;
649 disposeCOMInterfaces();
650 if (COM.FreeUnusedLibraries) {
651 COM.CoFreeUnusedLibraries();
659 if (control == null || control.isDisposed()) return;
660 long handle = control.handle;
661 RECT lpRect = new RECT();
662 if (OS.GetUpdateRect(handle, lpRect, false)) {
663 OS.ImageList_DragShowNolock(false);
664 OS.RedrawWindow(handle, lpRect, 0, OS.RDW_UPDATENOW | OS.RDW_INVALIDATE);
665 OS.ImageList_DragShowNolock(true);
670 * Removes the listener from the collection of listeners who will
671 * be notified when a drag and drop operation is in progress.
673 * @param listener the listener which should no longer be notified
675 * @exception IllegalArgumentException <ul>
676 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
678 * @exception SWTException <ul>
679 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
680 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
683 * @see DropTargetListener
684 * @see #addDropListener
685 * @see #getDropListeners
687 public void removeDropListener(DropTargetListener listener) {
688 if (listener == null) DND.error (SWT.ERROR_NULL_ARGUMENT);
689 removeListener (DND.DragEnter, listener);
690 removeListener (DND.DragLeave, listener);
691 removeListener (DND.DragOver, listener);
692 removeListener (DND.DragOperationChanged, listener);
693 removeListener (DND.Drop, listener);
694 removeListener (DND.DropAccept, listener);
698 * Specifies the drop effect for this DropTarget. This drop effect will be
699 * used during a drag and drop to display the drag under effect on the
702 * @param effect the drop effect that is registered for this DropTarget
706 public void setDropTargetEffect(DropTargetEffect effect) {
710 boolean setEventData(DNDEvent event, long pDataObject, int grfKeyState, int pt_x, int pt_y, long pdwEffect) {
711 if (pDataObject == 0 || pdwEffect == 0) return false;
713 // get allowed operations
714 int style = getStyle();
715 int[] operations = new int[1];
716 OS.MoveMemory(operations, pdwEffect, 4);
717 operations[0] = osToOp(operations[0]) & style;
718 if (operations[0] == DND.DROP_NONE) return false;
720 // get current operation
721 int operation = getOperationFromKeyState(grfKeyState);
722 keyOperation = operation;
723 if (operation == DND.DROP_DEFAULT) {
724 if ((style & DND.DROP_DEFAULT) == 0) {
725 operation = (operations[0] & DND.DROP_MOVE) != 0 ? DND.DROP_MOVE : DND.DROP_NONE;
728 if ((operation & operations[0]) == 0) operation = DND.DROP_NONE;
731 // Get allowed transfer types
732 TransferData[] dataTypes = new TransferData[0];
733 IDataObject dataObject = new IDataObject(pDataObject);
736 long[] address = new long[1];
737 if (dataObject.EnumFormatEtc(COM.DATADIR_GET, address) != COM.S_OK) {
740 IEnumFORMATETC enumFormatetc = new IEnumFORMATETC(address[0]);
742 // Loop over enumerator and save any types that match what we are looking for
743 long rgelt = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, FORMATETC.sizeof);
745 int[] pceltFetched = new int[1];
746 enumFormatetc.Reset();
747 while (enumFormatetc.Next(1, rgelt, pceltFetched) == COM.S_OK && pceltFetched[0] == 1) {
748 TransferData transferData = new TransferData();
749 transferData.formatetc = new FORMATETC();
750 COM.MoveMemory(transferData.formatetc, rgelt, FORMATETC.sizeof);
751 transferData.type = transferData.formatetc.cfFormat;
752 transferData.pIDataObject = pDataObject;
753 for (int i = 0; i < transferAgents.length; i++){
754 Transfer transfer = transferAgents[i];
755 if (transfer != null && transfer.isSupportedType(transferData)){
756 TransferData[] newDataTypes = new TransferData[dataTypes.length + 1];
757 System.arraycopy(dataTypes, 0, newDataTypes, 0, dataTypes.length);
758 newDataTypes[dataTypes.length] = transferData;
759 dataTypes = newDataTypes;
765 OS.GlobalFree(rgelt);
768 enumFormatetc.Release();
771 dataObject.Release();
773 if (dataTypes.length == 0) return false;
778 event.time = OS.GetMessageTime();
779 event.feedback = DND.FEEDBACK_SELECT;
780 event.dataTypes = dataTypes;
781 event.dataType = dataTypes[0];
782 if (dropEffect != null) {
783 event.item = dropEffect.getItem(pt_x, pt_y);
785 event.operations = operations[0];
786 event.detail = operation;
791 * Specifies the data types that can be transferred to this DropTarget. If data is
792 * being dragged that does not match one of these types, the drop target will be notified of
793 * the drag and drop operation but the currentDataType will be null and the operation
796 * @param transferAgents a list of Transfer objects which define the types of data that can be
797 * dropped on this target
799 * @exception IllegalArgumentException <ul>
800 * <li>ERROR_NULL_ARGUMENT - if transferAgents is null</li>
803 public void setTransfer(Transfer... transferAgents){
804 if (transferAgents == null) DND.error(SWT.ERROR_NULL_ARGUMENT);
805 this.transferAgents = transferAgents;