comparison org.eclipse.swt.win32.win32.x86/src/org/eclipse/swt/dnd/DragSource.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 d46287db17ed
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.DragSource;
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.graphics.Image;
20 import org.eclipse.swt.graphics.Point;
21 import org.eclipse.swt.internal.ImageList;
22 import org.eclipse.swt.internal.ole.win32.COM;
23 import org.eclipse.swt.internal.ole.win32.OLEIDL;
24 import org.eclipse.swt.internal.ole.win32.OBJIDL;
25 import org.eclipse.swt.internal.ole.win32.ifs;
26 import org.eclipse.swt.internal.ole.win32.extras;
27 import org.eclipse.swt.internal.win32.OS;
28 import org.eclipse.swt.widgets.Composite;
29 import org.eclipse.swt.widgets.Control;
30 import org.eclipse.swt.widgets.Display;
31 import org.eclipse.swt.widgets.Event;
32 import org.eclipse.swt.widgets.Listener;
33 import org.eclipse.swt.widgets.Table;
34 import org.eclipse.swt.widgets.Tree;
35 import org.eclipse.swt.widgets.Widget;
36
37 import org.eclipse.swt.dnd.DragSourceEffect;
38 import org.eclipse.swt.dnd.DragSourceListener;
39 import org.eclipse.swt.dnd.Transfer;
40 import org.eclipse.swt.dnd.TransferData;
41 import org.eclipse.swt.dnd.DND;
42 import org.eclipse.swt.dnd.DNDListener;
43 import org.eclipse.swt.dnd.DNDEvent;
44 import org.eclipse.swt.dnd.TreeDragSourceEffect;
45 import org.eclipse.swt.dnd.TableDragSourceEffect;
46 import org.eclipse.swt.dnd.OleEnumFORMATETC;
47
48 import java.lang.all;
49
50 /**
51 *
52 * <code>DragSource</code> defines the source object for a drag and drop transfer.
53 *
54 * <p>IMPORTANT: This class is <em>not</em> intended to be subclassed.</p>
55 *
56 * <p>A drag source is the object which originates a drag and drop operation. For the specified widget,
57 * it defines the type of data that is available for dragging and the set of operations that can
58 * be performed on that data. The operations can be any bit-wise combination of DND.MOVE, DND.COPY or
59 * DND.LINK. The type of data that can be transferred is specified by subclasses of Transfer such as
60 * TextTransfer or FileTransfer. The type of data transferred can be a predefined system type or it
61 * can be a type defined by the application. For instructions on how to define your own transfer type,
62 * refer to <code>ByteArrayTransfer</code>.</p>
63 *
64 * <p>You may have several DragSources in an application but you can only have one DragSource
65 * per Control. Data dragged from this DragSource can be dropped on a site within this application
66 * or it can be dropped on another application such as an external Text editor.</p>
67 *
68 * <p>The application supplies the content of the data being transferred by implementing the
69 * <code>DragSourceListener</code> and associating it with the DragSource via DragSource#addDragListener.</p>
70 *
71 * <p>When a successful move operation occurs, the application is required to take the appropriate
72 * action to remove the data from its display and remove any associated operating system resources or
73 * internal references. Typically in a move operation, the drop target makes a copy of the data
74 * and the drag source deletes the original. However, sometimes copying the data can take a long
75 * time (such as copying a large file). Therefore, on some platforms, the drop target may actually
76 * move the data in the operating system rather than make a copy. This is usually only done in
77 * file transfers. In this case, the drag source is informed in the DragEnd event that a
78 * DROP_TARGET_MOVE was performed. It is the responsibility of the drag source at this point to clean
79 * up its displayed information. No action needs to be taken on the operating system resources.</p>
80 *
81 * <p> The following example shows a Label widget that allows text to be dragged from it.</p>
82 *
83 * <code><pre>
84 * // Enable a label as a Drag Source
85 * Label label = new Label(shell, SWT.NONE);
86 * // This example will allow text to be dragged
87 * Transfer[] types = new Transfer[] {TextTransfer.getInstance()};
88 * // This example will allow the text to be copied or moved to the drop target
89 * int operations = DND.DROP_MOVE | DND.DROP_COPY;
90 *
91 * DragSource source = new DragSource(label, operations);
92 * source.setTransfer(types);
93 * source.addDragListener(new DragSourceListener() {
94 * public void dragStart(DragSourceEvent e) {
95 * // Only start the drag if there is actually text in the
96 * // label - this text will be what is dropped on the target.
97 * if (label.getText().length() is 0) {
98 * event.doit = false;
99 * }
100 * };
101 * public void dragSetData(DragSourceEvent event) {
102 * // A drop has been performed, so provide the data of the
103 * // requested type.
104 * // (Checking the type of the requested data is only
105 * // necessary if the drag source supports more than
106 * // one data type but is shown here as an example).
107 * if (TextTransfer.getInstance().isSupportedType(event.dataType)){
108 * event.data = label.getText();
109 * }
110 * }
111 * public void dragFinished(DragSourceEvent event) {
112 * // A Move operation has been performed so remove the data
113 * // from the source
114 * if (event.detail is DND.DROP_MOVE)
115 * label.setText("");
116 * }
117 * });
118 * </pre></code>
119 *
120 *
121 * <dl>
122 * <dt><b>Styles</b></dt> <dd>DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK</dd>
123 * <dt><b>Events</b></dt> <dd>DND.DragStart, DND.DragSetData, DND.DragEnd</dd>
124 * </dl>
125 *
126 * @see <a href="http://www.eclipse.org/swt/snippets/#dnd">Drag and Drop snippets</a>
127 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: DNDExample</a>
128 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
129 */
130 public class DragSource : Widget {
131
132 // info for registering as a drag source
133 Control control;
134 Listener controlListener;
135 Transfer[] transferAgents;
136 DragSourceEffect dragEffect;
137 Composite topControl;
138 HWND hwndDrag;
139
140 // ole interfaces
141 _IDropSourceImpl iDropSource;
142 _IDataObjectImpl iDataObject;
143 int refCount;
144
145 //workaround - track the operation performed by the drop target for DragEnd event
146 int dataEffect = DND.DROP_NONE;
147
148 static const String DEFAULT_DRAG_SOURCE_EFFECT = "DEFAULT_DRAG_SOURCE_EFFECT"; //$NON-NLS-1$
149 static const int CFSTR_PERFORMEDDROPEFFECT;
150 static final TCHAR[] WindowClass = "#32770\0";
151 static this(){
152 CFSTR_PERFORMEDDROPEFFECT = Transfer.registerType("Performed DropEffect"); //$NON-NLS-1$
153 }
154 /**
155 * Creates a new <code>DragSource</code> to handle dragging from the specified <code>Control</code>.
156 * Creating an instance of a DragSource may cause system resources to be allocated depending on the platform.
157 * It is therefore mandatory that the DragSource instance be disposed when no longer required.
158 *
159 * @param control the <code>Control</code> that the user clicks on to initiate the drag
160 * @param style the bitwise OR'ing of allowed operations; this may be a combination of any of
161 * DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK
162 *
163 * @exception SWTException <ul>
164 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
165 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
166 * </ul>
167 * @exception SWTError <ul>
168 * <li>ERROR_CANNOT_INIT_DRAG - unable to initiate drag source; this will occur if more than one
169 * drag source is created for a control or if the operating system will not allow the creation
170 * of the drag source</li>
171 * </ul>
172 *
173 * <p>NOTE: ERROR_CANNOT_INIT_DRAG should be an SWTException, since it is a
174 * recoverable error, but can not be changed due to backward compatibility.</p>
175 *
176 * @see Widget#dispose
177 * @see DragSource#checkSubclass
178 * @see DND#DROP_NONE
179 * @see DND#DROP_COPY
180 * @see DND#DROP_MOVE
181 * @see DND#DROP_LINK
182 */
183 public this(Control control, int style) {
184 super(control, checkStyle(style));
185 this.control = control;
186 if (control.getData(DND.DRAG_SOURCE_KEY) !is null) {
187 DND.error(DND.ERROR_CANNOT_INIT_DRAG);
188 }
189 control.setData(DND.DRAG_SOURCE_KEY, this);
190 createCOMInterfaces();
191 this.AddRef();
192
193 controlListener = new class() Listener {
194 public void handleEvent(Event event) {
195 if (event.type is SWT.Dispose) {
196 if (!this.outer.isDisposed()) {
197 this.outer.dispose();
198 }
199 }
200 if (event.type is SWT.DragDetect) {
201 if (!this.outer.isDisposed()) {
202 this.outer.drag(event);
203 }
204 }
205 }
206 };
207 control.addListener(SWT.Dispose, controlListener);
208 control.addListener(SWT.DragDetect, controlListener);
209
210 this.addListener(SWT.Dispose, new class() Listener {
211 public void handleEvent(Event e) {
212 this.outer.onDispose();
213 }
214 });
215
216 Object effect = control.getData(DEFAULT_DRAG_SOURCE_EFFECT);
217 if ( auto dse = cast(DragSourceEffect)effect ) {
218 dragEffect = dse;
219 } else if ( auto tree = cast(Tree)control ) {
220 dragEffect = new TreeDragSourceEffect(tree);
221 } else if ( auto table = cast(Table)control ) {
222 dragEffect = new TableDragSourceEffect(table);
223 }
224 }
225
226 static int checkStyle(int style) {
227 if (style is SWT.NONE) return DND.DROP_MOVE;
228 return style;
229 }
230
231 /**
232 * Adds the listener to the collection of listeners who will
233 * be notified when a drag and drop operation is in progress, by sending
234 * it one of the messages defined in the <code>DragSourceListener</code>
235 * interface.
236 *
237 * <p><ul>
238 * <li><code>dragStart</code> is called when the user has begun the actions required to drag the widget.
239 * This event gives the application the chance to decide if a drag should be started.
240 * <li><code>dragSetData</code> is called when the data is required from the drag source.
241 * <li><code>dragFinished</code> is called when the drop has successfully completed (mouse up
242 * over a valid target) or has been terminated (such as hitting the ESC key). Perform cleanup
243 * such as removing data from the source side on a successful move operation.
244 * </ul></p>
245 *
246 * @param listener the listener which should be notified
247 *
248 * @exception IllegalArgumentException <ul>
249 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
250 * </ul>
251 * @exception SWTException <ul>
252 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
253 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
254 * </ul>
255 *
256 * @see DragSourceListener
257 * @see #getDragListeners
258 * @see #removeDragListener
259 * @see DragSourceEvent
260 */
261 public void addDragListener(DragSourceListener listener) {
262 if (listener is null) DND.error(SWT.ERROR_NULL_ARGUMENT);
263 DNDListener typedListener = new DNDListener(listener);
264 typedListener.dndWidget = this;
265 addListener(DND.DragStart, typedListener);
266 addListener(DND.DragSetData, typedListener);
267 addListener(DND.DragEnd, typedListener);
268 }
269
270 private int AddRef() {
271 refCount++;
272 return refCount;
273 }
274
275 private void createCOMInterfaces() {
276 // register each of the interfaces that this object implements
277 iDropSource = new _IDropSourceImpl(this);
278 iDataObject = new _IDataObjectImpl(this);
279 }
280
281 protected void checkSubclass() {
282 String name = this.classinfo.name;
283 String validName = DragSource.classinfo.name;
284 if (validName!=/*eq*/name) {
285 DND.error(SWT.ERROR_INVALID_SUBCLASS);
286 }
287 }
288
289 private void disposeCOMInterfaces() {
290 iDropSource = null;
291 iDataObject = null;
292 }
293
294 private void drag(Event dragEvent) {
295 DNDEvent event = new DNDEvent();
296 event.widget = this;
297 event.x = dragEvent.x;
298 event.y = dragEvent.y;
299 event.time = OS.GetMessageTime();
300 event.doit = true;
301 notifyListeners(DND.DragStart,event);
302 if (!event.doit || transferAgents is null || transferAgents.length is 0 ) return;
303
304 uint[1] pdwEffect;
305 int operations = opToOs(getStyle());
306 Display display = control.getDisplay();
307 String key = "org.eclipse.swt.internal.win32.runMessagesInIdle"; //$NON-NLS-1$
308 Object oldValue = display.getData(key);
309 display.setData(key, new Boolean(true));
310 ImageList imagelist = null;
311 Image image = event.image;
312 hwndDrag = null;
313 topControl = null;
314 if (image !is null) {
315 imagelist = new ImageList(SWT.NONE);
316 imagelist.add(image);
317 topControl = control.getShell();
318 /*
319 * Bug in Windows. The image is inverted if the shell is RIGHT_TO_LEFT.
320 * The fix is to create a transparent window that covers the shell client
321 * area and use it during the drag to prevent the image from being inverted.
322 * On XP if the shell is RTL, the image is not displayed.
323 */
324 int offset = event.x - dragEvent.x;
325 hwndDrag = topControl.handle;
326 if ((topControl.getStyle() & SWT.RIGHT_TO_LEFT) !is 0) {
327 offset = image.getBounds().width - offset;
328 RECT rect;
329 OS.GetClientRect (topControl.handle, &rect);
330 hwndDrag = OS.CreateWindowEx (
331 OS.WS_EX_TRANSPARENT | OS.WS_EX_NOINHERITLAYOUT,
332 WindowClass.ptr,
333 null,
334 OS.WS_CHILD | OS.WS_CLIPSIBLINGS,
335 0, 0,
336 rect.right - rect.left, rect.bottom - rect.top,
337 topControl.handle,
338 null,
339 OS.GetModuleHandle (null),
340 null);
341 OS.ShowWindow (hwndDrag, OS.SW_SHOW);
342 }
343 OS.ImageList_BeginDrag(imagelist.getHandle(), 0, offset, event.y - dragEvent.y);
344 /*
345 * Feature in Windows. When ImageList_DragEnter() is called,
346 * it takes a snapshot of the screen If a drag is started
347 * when another window is in front, then the snapshot will
348 * contain part of the other window, causing pixel corruption.
349 * The fix is to force all paints to be delivered before
350 * calling ImageList_DragEnter().
351 */
352 if (OS.IsWinCE) {
353 OS.UpdateWindow (topControl.handle);
354 } else {
355 int flags = OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN;
356 OS.RedrawWindow (topControl.handle, null, null, flags);
357 }
358 POINT pt;
359 pt.x = dragEvent.x;
360 pt.y = dragEvent.y;
361 OS.MapWindowPoints (control.handle, null, &pt, 1);
362 RECT rect;
363 OS.GetWindowRect (hwndDrag, &rect);
364 OS.ImageList_DragEnter(hwndDrag, pt.x - rect.left, pt.y - rect.top);
365 }
366 int result = COM.DRAGDROP_S_CANCEL;
367 try {
368 result = COM.DoDragDrop(iDataObject, iDropSource, operations, pdwEffect.ptr);
369 } finally {
370 // ensure that we don't leave transparent window around
371 if (hwndDrag !is null) {
372 OS.ImageList_DragLeave(hwndDrag);
373 OS.ImageList_EndDrag();
374 imagelist.dispose();
375 if (hwndDrag !is topControl.handle) OS.DestroyWindow(hwndDrag);
376 hwndDrag = null;
377 topControl = null;
378 }
379 display.setData(key, oldValue);
380 }
381 int operation = osToOp(pdwEffect[0]);
382 if (dataEffect is DND.DROP_MOVE) {
383 operation = (operation is DND.DROP_NONE || operation is DND.DROP_COPY) ? DND.DROP_TARGET_MOVE : DND.DROP_MOVE;
384 } else {
385 if (dataEffect !is DND.DROP_NONE) {
386 operation = dataEffect;
387 }
388 }
389 event = new DNDEvent();
390 event.widget = this;
391 event.time = OS.GetMessageTime();
392 event.doit = (result is COM.DRAGDROP_S_DROP);
393 event.detail = operation;
394 notifyListeners(DND.DragEnd,event);
395 dataEffect = DND.DROP_NONE;
396 }
397 /*
398 * EnumFormatEtc([in] dwDirection, [out] ppenumFormatetc)
399 * Ownership of ppenumFormatetc transfers from callee to caller so reference count on ppenumFormatetc
400 * must be incremented before returning. Caller is responsible for releasing ppenumFormatetc.
401 */
402 private int EnumFormatEtc(int dwDirection, IEnumFORMATETC* ppenumFormatetc) {
403 // only allow getting of data - SetData is not currently supported
404 if (dwDirection is COM.DATADIR_SET) return COM.E_NOTIMPL;
405
406 // what types have been registered?
407 TransferData[] allowedDataTypes = new TransferData[0];
408 for (int i = 0; i < transferAgents.length; i++){
409 Transfer transferAgent = transferAgents[i];
410 if (transferAgent !is null) {
411 TransferData[] formats = transferAgent.getSupportedTypes();
412 TransferData[] newAllowedDataTypes = new TransferData[allowedDataTypes.length + formats.length];
413 System.arraycopy(allowedDataTypes, 0, newAllowedDataTypes, 0, allowedDataTypes.length);
414 System.arraycopy(formats, 0, newAllowedDataTypes, allowedDataTypes.length, formats.length);
415 allowedDataTypes = newAllowedDataTypes;
416 }
417 }
418
419 OleEnumFORMATETC enumFORMATETC = new OleEnumFORMATETC();
420 enumFORMATETC.AddRef();
421
422 FORMATETC*[] formats = new FORMATETC*[allowedDataTypes.length];
423 for (int i = 0; i < formats.length; i++){
424 formats[i] = allowedDataTypes[i].formatetc;
425 }
426 enumFORMATETC.setFormats(formats);
427
428 *ppenumFormatetc = enumFORMATETC.getAddress();
429 return COM.S_OK;
430 }
431 /**
432 * Returns the Control which is registered for this DragSource. This is the control that the
433 * user clicks in to initiate dragging.
434 *
435 * @return the Control which is registered for this DragSource
436 */
437 public Control getControl() {
438 return control;
439 }
440
441 .LRESULT GetData(FORMATETC *pFormatetc, STGMEDIUM *pmedium) {
442 /* Called by a data consumer to obtain data from a source data object.
443 The GetData method renders the data described in the specified FORMATETC
444 structure and transfers it through the specified STGMEDIUM structure.
445 The caller then assumes responsibility for releasing the STGMEDIUM structure.
446 */
447 if (pFormatetc is null || pmedium is null) return COM.E_INVALIDARG;
448
449 if (QueryGetData(pFormatetc) !is COM.S_OK) return COM.DV_E_FORMATETC;
450
451 TransferData transferData = new TransferData();
452 transferData.formatetc = new FORMATETC();
453 COM.MoveMemory(transferData.formatetc, pFormatetc, FORMATETC.sizeof);
454 transferData.type = transferData.formatetc.cfFormat;
455 transferData.stgmedium = new STGMEDIUM();
456 transferData.result = COM.E_FAIL;
457
458 DNDEvent event = new DNDEvent();
459 event.widget = this;
460 event.time = OS.GetMessageTime();
461 event.dataType = transferData;
462 notifyListeners(DND.DragSetData,event);
463
464 // get matching transfer agent to perform conversion
465 Transfer transfer = null;
466 for (int i = 0; i < transferAgents.length; i++){
467 Transfer transferAgent = transferAgents[i];
468 if (transferAgent !is null && transferAgent.isSupportedType(transferData)){
469 transfer = transferAgent;
470 break;
471 }
472 }
473
474 if (transfer is null) return COM.DV_E_FORMATETC;
475 transfer.javaToNative(event.data, transferData);
476 if (transferData.result !is COM.S_OK) return transferData.result;
477 COM.MoveMemory(pmedium, transferData.stgmedium, STGMEDIUM.sizeof);
478 return transferData.result;
479 }
480
481 /**
482 * Returns an array of listeners who will be notified when a drag and drop
483 * operation is in progress, by sending it one of the messages defined in
484 * the <code>DragSourceListener</code> interface.
485 *
486 * @return the listeners who will be notified when a drag and drop
487 * operation is in progress
488 *
489 * @exception SWTException <ul>
490 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
491 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
492 * </ul>
493 *
494 * @see DragSourceListener
495 * @see #addDragListener
496 * @see #removeDragListener
497 * @see DragSourceEvent
498 *
499 * @since 3.4
500 */
501 public DragSourceListener[] getDragListeners() {
502 Listener[] listeners = getListeners(DND.DragStart);
503 int length = listeners.length;
504 DragSourceListener[] dragListeners = new DragSourceListener[length];
505 int count = 0;
506 for (int i = 0; i < length; i++) {
507 Listener listener = listeners[i];
508 if ( auto l = cast(DNDListener)listener ) {
509 dragListeners[count] = cast(DragSourceListener) (l.getEventListener());
510 count++;
511 }
512 }
513 if (count is length) return dragListeners;
514 DragSourceListener[] result = new DragSourceListener[count];
515 SimpleType!(DragSourceListener).arraycopy(dragListeners, 0, result, 0, count);
516 return result;
517 }
518
519 /**
520 * Returns the drag effect that is registered for this DragSource. This drag
521 * effect will be used during a drag and drop operation.
522 *
523 * @return the drag effect that is registered for this DragSource
524 *
525 * @since 3.3
526 */
527 public DragSourceEffect getDragSourceEffect() {
528 return dragEffect;
529 }
530
531 /**
532 * Returns the list of data types that can be transferred by this DragSource.
533 *
534 * @return the list of data types that can be transferred by this DragSource
535 */
536 public Transfer[] getTransfer(){
537 return transferAgents;
538 }
539
540 package .LRESULT GiveFeedback(DWORD dwEffect) {
541 return COM.DRAGDROP_S_USEDEFAULTCURSORS;
542 }
543
544 package .LRESULT QueryContinueDrag(int fEscapePressed, DWORD grfKeyState) {
545 if (topControl !is null && topControl.isDisposed()) return COM.DRAGDROP_S_CANCEL;
546 if (fEscapePressed !is 0){
547 if (hwndDrag !is null) OS.ImageList_DragLeave(hwndDrag);
548 return COM.DRAGDROP_S_CANCEL;
549 }
550 /*
551 * Bug in Windows. On some machines that do not have XBUTTONs,
552 * the MK_XBUTTON1 and OS.MK_XBUTTON2 bits are sometimes set,
553 * causing mouse capture to become stuck. The fix is to test
554 * for the extra buttons only when they exist.
555 */
556 int mask = OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON;
557 // if (display.xMouse) mask |= OS.MK_XBUTTON1 | OS.MK_XBUTTON2;
558 if ((grfKeyState & mask) is 0) {
559 if (hwndDrag !is null) OS.ImageList_DragLeave(hwndDrag);
560 return COM.DRAGDROP_S_DROP;
561 }
562
563 if (hwndDrag !is null) {
564 POINT pt;
565 OS.GetCursorPos (&pt);
566 RECT rect;
567 OS.GetWindowRect (hwndDrag, &rect);
568 OS.ImageList_DragMove (pt.x - rect.left, pt.y - rect.top);
569 }
570 return COM.S_OK;
571 }
572
573 private void onDispose() {
574 if (control is null) return;
575 this.Release();
576 if (controlListener !is null){
577 control.removeListener(SWT.Dispose, controlListener);
578 control.removeListener(SWT.DragDetect, controlListener);
579 }
580 controlListener = null;
581 control.setData(DND.DRAG_SOURCE_KEY, null);
582 control = null;
583 transferAgents = null;
584 }
585
586 private int opToOs(int operation) {
587 int osOperation = 0;
588 if ((operation & DND.DROP_COPY) !is 0){
589 osOperation |= COM.DROPEFFECT_COPY;
590 }
591 if ((operation & DND.DROP_LINK) !is 0) {
592 osOperation |= COM.DROPEFFECT_LINK;
593 }
594 if ((operation & DND.DROP_MOVE) !is 0) {
595 osOperation |= COM.DROPEFFECT_MOVE;
596 }
597 return osOperation;
598 }
599
600 private int osToOp(int osOperation){
601 int operation = 0;
602 if ((osOperation & COM.DROPEFFECT_COPY) !is 0){
603 operation |= DND.DROP_COPY;
604 }
605 if ((osOperation & COM.DROPEFFECT_LINK) !is 0) {
606 operation |= DND.DROP_LINK;
607 }
608 if ((osOperation & COM.DROPEFFECT_MOVE) !is 0) {
609 operation |= DND.DROP_MOVE;
610 }
611 return operation;
612 }
613
614 private .LRESULT QueryGetData(FORMATETC* pFormatetc) {
615 if (transferAgents is null) return COM.E_FAIL;
616 TransferData transferData = new TransferData();
617 transferData.formatetc = new FORMATETC();
618 COM.MoveMemory(transferData.formatetc, pFormatetc, FORMATETC.sizeof);
619 transferData.type = transferData.formatetc.cfFormat;
620
621 // is this type supported by the transfer agent?
622 for (int i = 0; i < transferAgents.length; i++){
623 Transfer transfer = transferAgents[i];
624 if (transfer !is null && transfer.isSupportedType(transferData))
625 return COM.S_OK;
626 }
627
628 return COM.DV_E_FORMATETC;
629 }
630
631 /* QueryInterface([in] riid, [out] ppvObject)
632 * Ownership of ppvObject transfers from callee to caller so reference count on ppvObject
633 * must be incremented before returning. Caller is responsible for releasing ppvObject.
634 */
635 private HRESULT QueryInterface(REFIID riid, void** ppvObject) {
636 if (riid is null || ppvObject is null)
637 return COM.E_INVALIDARG;
638
639 if (COM.IsEqualGUID(riid, &COM.IIDIUnknown) || COM.IsEqualGUID(riid, &COM.IIDIDropSource)) {
640 *ppvObject = cast(void*)cast(IUnknown) iDropSource;
641 AddRef();
642 return COM.S_OK;
643 }
644
645 if (COM.IsEqualGUID(riid, &COM.IIDIDataObject) ) {
646 *ppvObject = cast(void*)cast(IDataObject) iDataObject;
647 AddRef();
648 return COM.S_OK;
649 }
650
651 *ppvObject = null;
652 return COM.E_NOINTERFACE;
653 }
654
655 private ULONG Release() {
656 refCount--;
657 if (refCount is 0) {
658 disposeCOMInterfaces();
659 COM.CoFreeUnusedLibraries();
660 }
661 return refCount;
662 }
663
664 /**
665 * Removes the listener from the collection of listeners who will
666 * be notified when a drag and drop operation is in progress.
667 *
668 * @param listener the listener which should no longer be notified
669 *
670 * @exception IllegalArgumentException <ul>
671 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
672 * </ul>
673 * @exception SWTException <ul>
674 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
675 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
676 * </ul>
677 *
678 * @see DragSourceListener
679 * @see #addDragListener
680 * @see #getDragListeners
681 */
682 public void removeDragListener(DragSourceListener listener) {
683 if (listener is null) DND.error(SWT.ERROR_NULL_ARGUMENT);
684 removeListener(DND.DragStart, listener);
685 removeListener(DND.DragSetData, listener);
686 removeListener(DND.DragEnd, listener);
687 }
688
689 .LRESULT SetData(FORMATETC* pFormatetc, STGMEDIUM* pmedium, int fRelease) {
690 if (pFormatetc is null || pmedium is null) return COM.E_INVALIDARG;
691 FORMATETC* formatetc = new FORMATETC();
692 COM.MoveMemory(formatetc, pFormatetc, FORMATETC.sizeof);
693 if (formatetc.cfFormat is CFSTR_PERFORMEDDROPEFFECT && formatetc.tymed is COM.TYMED_HGLOBAL) {
694 STGMEDIUM* stgmedium = new STGMEDIUM();
695 COM.MoveMemory(stgmedium, pmedium,STGMEDIUM.sizeof);
696 //TODO - this should be GlobalLock()
697 int[1] ptrEffect;
698 OS.MoveMemory(ptrEffect.ptr, stgmedium.unionField,4);
699 int[1] effect;
700 OS.MoveMemory(effect.ptr, ptrEffect[0],4);
701 dataEffect = osToOp(effect[0]);
702 }
703 if (fRelease is 1) {
704 COM.ReleaseStgMedium(pmedium);
705 }
706 return COM.S_OK;
707 }
708
709 /**
710 * Specifies the drag effect for this DragSource. This drag effect will be
711 * used during a drag and drop operation.
712 *
713 * @param effect the drag effect that is registered for this DragSource
714 *
715 * @since 3.3
716 */
717 public void setDragSourceEffect(DragSourceEffect effect) {
718 dragEffect = effect;
719 }
720
721 /**
722 * Specifies the list of data types that can be transferred by this DragSource.
723 * The application must be able to provide data to match each of these types when
724 * a successful drop has occurred.
725 *
726 * @param transferAgents a list of Transfer objects which define the types of data that can be
727 * dragged from this source
728 */
729 public void setTransfer(Transfer[] transferAgents){
730 this.transferAgents = transferAgents;
731 }
732
733 }
734
735
736 private class _IDropSourceImpl : IDropSource {
737
738 DragSource parent;
739 this(DragSource p) { parent = p; }
740 extern (Windows):
741 // interface of IUnknown
742 HRESULT QueryInterface(REFIID riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); }
743 ULONG AddRef() { return parent.AddRef(); }
744 ULONG Release() { return parent.Release(); }
745
746 // interface of IDropSource
747 HRESULT QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) { return parent.QueryContinueDrag(fEscapePressed, grfKeyState); }
748 HRESULT GiveFeedback(DWORD dwEffect) { return parent.GiveFeedback(dwEffect);}
749 }
750
751 private class _IDataObjectImpl : IDataObject {
752
753 DragSource parent;
754 this(DragSource p) { parent = p; }
755 extern (Windows):
756 // interface of IUnknown
757 HRESULT QueryInterface(REFIID riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); }
758 ULONG AddRef() { return parent.AddRef(); }
759 ULONG Release() { return parent.Release(); }
760
761
762 // interface IDataObject
763 LRESULT GetData( FORMATETC *pFormatetc, STGMEDIUM *pmedium) { return parent.GetData(pFormatetc, pmedium); }
764 LRESULT GetDataHere(FORMATETC * pFormatetc, STGMEDIUM * pmedium) { return COM.E_NOTIMPL; }
765 LRESULT QueryGetData(FORMATETC* pFormatetc) { return parent.QueryGetData(pFormatetc); }
766 LRESULT GetCanonicalFormatEtc(FORMATETC* pFormatetcIn, FORMATETC* pFormatetcOut) { return COM.E_NOTIMPL; }
767 LRESULT SetData(FORMATETC* pFormatetc, STGMEDIUM * pmedium, BOOL fRelease) { return parent.SetData(pFormatetc, pmedium, fRelease); }
768 LRESULT EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC * ppenumFormatetc) { return parent.EnumFormatEtc(dwDirection, ppenumFormatetc); }
769 LRESULT DAdvise(FORMATETC* pFormatetc, DWORD advf, IAdviseSink pAdvSink, DWORD* pdwConnection) { return COM.E_NOTIMPL; }
770 LRESULT DUnadvise(DWORD dwConnection) { return COM.E_NOTIMPL; }
771 LRESULT EnumDAdvise(IEnumSTATDATA * ppenumAdvise) { return COM.E_NOTIMPL; }
772 }