Mercurial > projects > dwt2
comparison org.eclipse.swt.win32.win32.x86/src/org/eclipse/swt/dnd/DropTarget.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.DropTarget; | |
14 | |
15 import org.eclipse.swt.SWT; | |
16 import org.eclipse.swt.SWTError; | |
17 import org.eclipse.swt.SWTException; | |
18 import org.eclipse.swt.internal.C; | |
19 import org.eclipse.swt.internal.ole.win32.COM; | |
20 import org.eclipse.swt.internal.ole.win32.extras; | |
21 import org.eclipse.swt.internal.ole.win32.OBJIDL; | |
22 import org.eclipse.swt.internal.ole.win32.OLEIDL; | |
23 import org.eclipse.swt.internal.ole.win32.ifs; | |
24 import org.eclipse.swt.internal.win32.OS; | |
25 import org.eclipse.swt.widgets.Control; | |
26 import org.eclipse.swt.widgets.Event; | |
27 import org.eclipse.swt.widgets.Listener; | |
28 import org.eclipse.swt.widgets.Table; | |
29 import org.eclipse.swt.widgets.Tree; | |
30 import org.eclipse.swt.widgets.Widget; | |
31 | |
32 import org.eclipse.swt.dnd.Transfer; | |
33 import org.eclipse.swt.dnd.DropTargetEffect; | |
34 import org.eclipse.swt.dnd.TransferData; | |
35 import org.eclipse.swt.dnd.DropTargetListener; | |
36 import org.eclipse.swt.dnd.DNDListener; | |
37 import org.eclipse.swt.dnd.DNDEvent; | |
38 import org.eclipse.swt.dnd.DND; | |
39 import org.eclipse.swt.dnd.TableDropTargetEffect; | |
40 import org.eclipse.swt.dnd.TreeDropTargetEffect; | |
41 | |
42 import java.lang.all; | |
43 | |
44 /** | |
45 * | |
46 * Class <code>DropTarget</code> defines the target object for a drag and drop transfer. | |
47 * | |
48 * IMPORTANT: This class is <em>not</em> intended to be subclassed. | |
49 * | |
50 * <p>This class identifies the <code>Control</code> over which the user must position the cursor | |
51 * in order to drop the data being transferred. It also specifies what data types can be dropped on | |
52 * this control and what operations can be performed. You may have several DropTragets in an | |
53 * application but there can only be a one to one mapping between a <code>Control</code> and a <code>DropTarget</code>. | |
54 * The DropTarget can receive data from within the same application or from other applications | |
55 * (such as text dragged from a text editor like Word).</p> | |
56 * | |
57 * <code><pre> | |
58 * int operations = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK; | |
59 * Transfer[] types = new Transfer[] {TextTransfer.getInstance()}; | |
60 * DropTarget target = new DropTarget(label, operations); | |
61 * target.setTransfer(types); | |
62 * </code></pre> | |
63 * | |
64 * <p>The application is notified of data being dragged over this control and of when a drop occurs by | |
65 * implementing the interface <code>DropTargetListener</code> which uses the class | |
66 * <code>DropTargetEvent</code>. The application can modify the type of drag being performed | |
67 * on this Control at any stage of the drag by modifying the <code>event.detail</code> field or the | |
68 * <code>event.currentDataType</code> field. When the data is dropped, it is the responsibility of | |
69 * the application to copy this data for its own purposes. | |
70 * | |
71 * <code><pre> | |
72 * target.addDropListener (new DropTargetListener() { | |
73 * public void dragEnter(DropTargetEvent event) {}; | |
74 * public void dragOver(DropTargetEvent event) {}; | |
75 * public void dragLeave(DropTargetEvent event) {}; | |
76 * public void dragOperationChanged(DropTargetEvent event) {}; | |
77 * public void dropAccept(DropTargetEvent event) {} | |
78 * public void drop(DropTargetEvent event) { | |
79 * // A drop has occurred, copy over the data | |
80 * if (event.data is null) { // no data to copy, indicate failure in event.detail | |
81 * event.detail = DND.DROP_NONE; | |
82 * return; | |
83 * } | |
84 * label.setText ((String) event.data); // data copied to label text | |
85 * } | |
86 * }); | |
87 * </pre></code> | |
88 * | |
89 * <dl> | |
90 * <dt><b>Styles</b></dt> <dd>DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK</dd> | |
91 * <dt><b>Events</b></dt> <dd>DND.DragEnter, DND.DragLeave, DND.DragOver, DND.DragOperationChanged, | |
92 * DND.DropAccept, DND.Drop </dd> | |
93 * </dl> | |
94 * | |
95 * @see <a href="http://www.eclipse.org/swt/snippets/#dnd">Drag and Drop snippets</a> | |
96 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: DNDExample</a> | |
97 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> | |
98 */ | |
99 public class DropTarget : Widget { | |
100 | |
101 Control control; | |
102 Listener controlListener; | |
103 Transfer[] transferAgents; | |
104 DropTargetEffect dropEffect; | |
105 | |
106 // Track application selections | |
107 TransferData selectedDataType; | |
108 int selectedOperation; | |
109 | |
110 // workaround - There is no event for "operation changed" so track operation based on key state | |
111 int keyOperation = -1; | |
112 | |
113 // workaround - The dataobject address is only passed as an argument in drag enter and drop. | |
114 // To allow applications to query the data values during the drag over operations, | |
115 // maintain a reference to it. | |
116 IDataObject iDataObject; | |
117 | |
118 // interfaces | |
119 _IDropTargetImpl iDropTarget; | |
120 int refCount; | |
121 | |
122 static final String DEFAULT_DROP_TARGET_EFFECT = "DEFAULT_DROP_TARGET_EFFECT"; //$NON-NLS-1$ | |
123 | |
124 /** | |
125 * Creates a new <code>DropTarget</code> to allow data to be dropped on the specified | |
126 * <code>Control</code>. | |
127 * Creating an instance of a DropTarget may cause system resources to be allocated | |
128 * depending on the platform. It is therefore mandatory that the DropTarget instance | |
129 * be disposed when no longer required. | |
130 * | |
131 * @param control the <code>Control</code> over which the user positions the cursor to drop the data | |
132 * @param style the bitwise OR'ing of allowed operations; this may be a combination of any of | |
133 * DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK | |
134 * | |
135 * @exception SWTException <ul> | |
136 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> | |
137 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> | |
138 * </ul> | |
139 * @exception SWTError <ul> | |
140 * <li>ERROR_CANNOT_INIT_DROP - unable to initiate drop target; this will occur if more than one | |
141 * drop target is created for a control or if the operating system will not allow the creation | |
142 * of the drop target</li> | |
143 * </ul> | |
144 * | |
145 * <p>NOTE: ERROR_CANNOT_INIT_DROP should be an SWTException, since it is a | |
146 * recoverable error, but can not be changed due to backward compatibility.</p> | |
147 * | |
148 * @see Widget#dispose | |
149 * @see DropTarget#checkSubclass | |
150 * @see DND#DROP_NONE | |
151 * @see DND#DROP_COPY | |
152 * @see DND#DROP_MOVE | |
153 * @see DND#DROP_LINK | |
154 */ | |
155 public this(Control control, int style) { | |
156 super (control, checkStyle(style)); | |
157 this.control = control; | |
158 if (control.getData(DND.DROP_TARGET_KEY) !is null) { | |
159 DND.error(DND.ERROR_CANNOT_INIT_DROP); | |
160 } | |
161 control.setData(DND.DROP_TARGET_KEY, this); | |
162 createCOMInterfaces(); | |
163 this.AddRef(); | |
164 | |
165 if (COM.CoLockObjectExternal(iDropTarget, true, true) !is COM.S_OK) | |
166 DND.error(DND.ERROR_CANNOT_INIT_DROP); | |
167 if (COM.RegisterDragDrop( control.handle, iDropTarget) !is COM.S_OK) | |
168 DND.error(DND.ERROR_CANNOT_INIT_DROP); | |
169 | |
170 controlListener = new class() Listener { | |
171 public void handleEvent (Event event) { | |
172 if (!this.outer.isDisposed()){ | |
173 this.outer.dispose(); | |
174 } | |
175 } | |
176 }; | |
177 control.addListener (SWT.Dispose, controlListener); | |
178 | |
179 this.addListener(SWT.Dispose, new class() Listener { | |
180 public void handleEvent (Event event) { | |
181 onDispose(); | |
182 } | |
183 }); | |
184 | |
185 Object effect = control.getData(DEFAULT_DROP_TARGET_EFFECT); | |
186 if ( auto dte = cast(DropTargetEffect) effect ) { | |
187 dropEffect = dte; | |
188 } else if ( auto table = cast(Table)control ) { | |
189 dropEffect = new TableDropTargetEffect(table); | |
190 } else if ( auto tree = cast(Tree)control ) { | |
191 dropEffect = new TreeDropTargetEffect(tree); | |
192 } | |
193 } | |
194 | |
195 static int checkStyle (int style) { | |
196 if (style is SWT.NONE) return DND.DROP_MOVE; | |
197 return style; | |
198 } | |
199 | |
200 /** | |
201 * Adds the listener to the collection of listeners who will | |
202 * be notified when a drag and drop operation is in progress, by sending | |
203 * it one of the messages defined in the <code>DropTargetListener</code> | |
204 * interface. | |
205 * | |
206 * <p><ul> | |
207 * <li><code>dragEnter</code> is called when the cursor has entered the drop target boundaries | |
208 * <li><code>dragLeave</code> is called when the cursor has left the drop target boundaries and just before | |
209 * the drop occurs or is cancelled. | |
210 * <li><code>dragOperationChanged</code> is called when the operation being performed has changed | |
211 * (usually due to the user changing the selected modifier key(s) while dragging) | |
212 * <li><code>dragOver</code> is called when the cursor is moving over the drop target | |
213 * <li><code>dropAccept</code> is called just before the drop is performed. The drop target is given | |
214 * the chance to change the nature of the drop or veto the drop by setting the <code>event.detail</code> field | |
215 * <li><code>drop</code> is called when the data is being dropped | |
216 * </ul></p> | |
217 * | |
218 * @param listener the listener which should be notified | |
219 * | |
220 * @exception IllegalArgumentException <ul> | |
221 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> | |
222 * </ul> | |
223 * @exception SWTException <ul> | |
224 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
225 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
226 * </ul> | |
227 * | |
228 * @see DropTargetListener | |
229 * @see #getDropListeners | |
230 * @see #removeDropListener | |
231 * @see DropTargetEvent | |
232 */ | |
233 public void addDropListener(DropTargetListener listener) { | |
234 if (listener is null) DND.error (SWT.ERROR_NULL_ARGUMENT); | |
235 DNDListener typedListener = new DNDListener (listener); | |
236 typedListener.dndWidget = this; | |
237 addListener (DND.DragEnter, typedListener); | |
238 addListener (DND.DragLeave, typedListener); | |
239 addListener (DND.DragOver, typedListener); | |
240 addListener (DND.DragOperationChanged, typedListener); | |
241 addListener (DND.Drop, typedListener); | |
242 addListener (DND.DropAccept, typedListener); | |
243 } | |
244 | |
245 ULONG AddRef() { | |
246 refCount++; | |
247 return refCount; | |
248 } | |
249 | |
250 protected void checkSubclass () { | |
251 String name = this.classinfo.name; | |
252 String validName = DropTarget.classinfo.name; | |
253 if (validName!=/*eq*/name) { | |
254 DND.error (SWT.ERROR_INVALID_SUBCLASS); | |
255 } | |
256 } | |
257 | |
258 void createCOMInterfaces() { | |
259 // register each of the interfaces that this object implements | |
260 iDropTarget = new _IDropTargetImpl(this); | |
261 } | |
262 | |
263 void disposeCOMInterfaces() { | |
264 iDropTarget = null; | |
265 } | |
266 | |
267 int DragEnter_64(IDataObject pDataObject, DWORD grfKeyState, long pt, DWORD* pdwEffect) { | |
268 POINTL point; | |
269 OS.MoveMemory( &point, &pt, 8); | |
270 return DragEnter(pDataObject, grfKeyState, point, pdwEffect); | |
271 } | |
272 | |
273 HRESULT DragEnter(IDataObject pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) { | |
274 selectedDataType = null; | |
275 selectedOperation = DND.DROP_NONE; | |
276 if (iDataObject !is null) iDataObject.Release(); | |
277 iDataObject = null; | |
278 | |
279 DNDEvent event = new DNDEvent(); | |
280 if (!setEventData(event, pDataObject, grfKeyState, pt, pdwEffect)) { | |
281 *pdwEffect = COM.DROPEFFECT_NONE; | |
282 return COM.S_FALSE; | |
283 } | |
284 | |
285 // Remember the iDataObject because it is not passed into the DragOver callback | |
286 iDataObject = pDataObject; | |
287 iDataObject.AddRef(); | |
288 | |
289 int allowedOperations = event.operations; | |
290 TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length]; | |
291 System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length); | |
292 notifyListeners(DND.DragEnter, event); | |
293 refresh(); | |
294 if (event.detail is DND.DROP_DEFAULT) { | |
295 event.detail = (allowedOperations & DND.DROP_MOVE) !is 0 ? DND.DROP_MOVE : DND.DROP_NONE; | |
296 } | |
297 | |
298 selectedDataType = null; | |
299 for (int i = 0; i < allowedDataTypes.length; i++) { | |
300 if (TransferData.sameType(allowedDataTypes[i], event.dataType)){ | |
301 selectedDataType = allowedDataTypes[i]; | |
302 break; | |
303 } | |
304 } | |
305 | |
306 selectedOperation = DND.DROP_NONE; | |
307 if (selectedDataType !is null && ((allowedOperations & event.detail) !is 0)) { | |
308 selectedOperation = event.detail; | |
309 } | |
310 | |
311 *pdwEffect = opToOs(selectedOperation); | |
312 return COM.S_OK; | |
313 } | |
314 | |
315 HRESULT DragLeave() { | |
316 keyOperation = -1; | |
317 | |
318 if (iDataObject is null) return COM.S_FALSE; | |
319 | |
320 DNDEvent event = new DNDEvent(); | |
321 event.widget = this; | |
322 event.time = OS.GetMessageTime(); | |
323 event.detail = DND.DROP_NONE; | |
324 notifyListeners(DND.DragLeave, event); | |
325 refresh(); | |
326 | |
327 iDataObject.Release(); | |
328 iDataObject = null; | |
329 return COM.S_OK; | |
330 } | |
331 | |
332 int DragOver_64(int grfKeyState, long pt, DWORD* pdwEffect) { | |
333 POINTL point; | |
334 OS.MoveMemory(&point, &pt, 8); | |
335 return DragOver(grfKeyState, point, pdwEffect); | |
336 } | |
337 | |
338 HRESULT DragOver(int grfKeyState, POINTL pt, DWORD* pdwEffect) { | |
339 if (iDataObject is null) return COM.S_FALSE; | |
340 int oldKeyOperation = keyOperation; | |
341 | |
342 DNDEvent event = new DNDEvent(); | |
343 if (!setEventData(event, iDataObject, grfKeyState, pt, pdwEffect)) { | |
344 keyOperation = -1; | |
345 *pdwEffect = COM.DROPEFFECT_NONE; | |
346 return COM.S_FALSE; | |
347 } | |
348 | |
349 int allowedOperations = event.operations; | |
350 TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length]; | |
351 System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length); | |
352 | |
353 if (keyOperation is oldKeyOperation) { | |
354 event.type = DND.DragOver; | |
355 event.dataType = selectedDataType; | |
356 event.detail = selectedOperation; | |
357 } else { | |
358 event.type = DND.DragOperationChanged; | |
359 event.dataType = selectedDataType; | |
360 } | |
361 notifyListeners(event.type, event); | |
362 refresh(); | |
363 if (event.detail is DND.DROP_DEFAULT) { | |
364 event.detail = (allowedOperations & DND.DROP_MOVE) !is 0 ? DND.DROP_MOVE : DND.DROP_NONE; | |
365 } | |
366 | |
367 selectedDataType = null; | |
368 for (int i = 0; i < allowedDataTypes.length; i++) { | |
369 if (TransferData.sameType(allowedDataTypes[i], event.dataType)){ | |
370 selectedDataType = allowedDataTypes[i]; | |
371 break; | |
372 } | |
373 } | |
374 | |
375 selectedOperation = DND.DROP_NONE; | |
376 if (selectedDataType !is null && ((allowedOperations & event.detail) is event.detail)) { | |
377 selectedOperation = event.detail; | |
378 } | |
379 | |
380 *pdwEffect = opToOs(selectedOperation); | |
381 return COM.S_OK; | |
382 } | |
383 | |
384 int Drop_64(IDataObject pDataObject, int grfKeyState, long pt, DWORD* pdwEffect) { | |
385 POINTL point; | |
386 OS.MoveMemory(&point, &pt, 8); | |
387 return Drop(pDataObject, grfKeyState, point, pdwEffect); | |
388 } | |
389 | |
390 HRESULT Drop(IDataObject pDataObject, int grfKeyState, POINTL pt, DWORD* pdwEffect) { | |
391 DNDEvent event = new DNDEvent(); | |
392 event.widget = this; | |
393 event.time = OS.GetMessageTime(); | |
394 if (dropEffect !is null) { | |
395 event.item = dropEffect.getItem(pt.x, pt.y); | |
396 } | |
397 event.detail = DND.DROP_NONE; | |
398 notifyListeners(DND.DragLeave, event); | |
399 refresh(); | |
400 | |
401 event = new DNDEvent(); | |
402 if (!setEventData(event, pDataObject, grfKeyState, pt, pdwEffect)) { | |
403 keyOperation = -1; | |
404 *pdwEffect = COM.DROPEFFECT_NONE; | |
405 return COM.S_FALSE; | |
406 } | |
407 keyOperation = -1; | |
408 int allowedOperations = event.operations; | |
409 TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length]; | |
410 System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length); | |
411 event.dataType = selectedDataType; | |
412 event.detail = selectedOperation; | |
413 notifyListeners(DND.DropAccept,event); | |
414 refresh(); | |
415 | |
416 selectedDataType = null; | |
417 for (int i = 0; i < allowedDataTypes.length; i++) { | |
418 if (TransferData.sameType(allowedDataTypes[i], event.dataType)){ | |
419 selectedDataType = allowedDataTypes[i]; | |
420 break; | |
421 } | |
422 } | |
423 selectedOperation = DND.DROP_NONE; | |
424 if (selectedDataType !is null && (allowedOperations & event.detail) is event.detail) { | |
425 selectedOperation = event.detail; | |
426 } | |
427 | |
428 if (selectedOperation is DND.DROP_NONE){ | |
429 *pdwEffect = COM.DROPEFFECT_NONE; | |
430 return COM.S_OK; | |
431 } | |
432 | |
433 // Get Data in a Java format | |
434 Object object = null; | |
435 for (int i = 0; i < transferAgents.length; i++){ | |
436 Transfer transfer = transferAgents[i]; | |
437 if (transfer !is null && transfer.isSupportedType(selectedDataType)){ | |
438 object = transfer.nativeToJava(selectedDataType); | |
439 break; | |
440 } | |
441 } | |
442 if (object is null){ | |
443 selectedOperation = DND.DROP_NONE; | |
444 } | |
445 | |
446 event.detail = selectedOperation; | |
447 event.dataType = selectedDataType; | |
448 event.data = object; | |
449 OS.ImageList_DragShowNolock(false); | |
450 try { | |
451 notifyListeners(DND.Drop,event); | |
452 } finally { | |
453 OS.ImageList_DragShowNolock(true); | |
454 } | |
455 refresh(); | |
456 selectedOperation = DND.DROP_NONE; | |
457 if ((allowedOperations & event.detail) is event.detail) { | |
458 selectedOperation = event.detail; | |
459 } | |
460 //notify source of action taken | |
461 *pdwEffect = opToOs(selectedOperation); | |
462 return COM.S_OK; | |
463 } | |
464 | |
465 /** | |
466 * Returns the Control which is registered for this DropTarget. This is the control over which the | |
467 * user positions the cursor to drop the data. | |
468 * | |
469 * @return the Control which is registered for this DropTarget | |
470 */ | |
471 public Control getControl () { | |
472 return control; | |
473 } | |
474 | |
475 /** | |
476 * Returns an array of listeners who will be notified when a drag and drop | |
477 * operation is in progress, by sending it one of the messages defined in | |
478 * the <code>DropTargetListener</code> interface. | |
479 * | |
480 * @return the listeners who will be notified when a drag and drop | |
481 * operation is in progress | |
482 * | |
483 * @exception SWTException <ul> | |
484 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
485 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
486 * </ul> | |
487 * | |
488 * @see DropTargetListener | |
489 * @see #addDropListener | |
490 * @see #removeDropListener | |
491 * @see DropTargetEvent | |
492 * | |
493 * @since 3.4 | |
494 */ | |
495 public DropTargetListener[] getDropListeners() { | |
496 Listener[] listeners = getListeners(DND.DragEnter); | |
497 int length = listeners.length; | |
498 DropTargetListener[] dropListeners = new DropTargetListener[length]; | |
499 int count = 0; | |
500 for (int i = 0; i < length; i++) { | |
501 Listener listener = listeners[i]; | |
502 if (auto l = cast(DNDListener)listener ) { | |
503 dropListeners[count] = cast(DropTargetListener) (l.getEventListener()); | |
504 count++; | |
505 } | |
506 } | |
507 if (count is length) return dropListeners; | |
508 DropTargetListener[] result = new DropTargetListener[count]; | |
509 SimpleType!(DropTargetListener).arraycopy(dropListeners, 0, result, 0, count); | |
510 return result; | |
511 } | |
512 | |
513 /** | |
514 * Returns the drop effect for this DropTarget. This drop effect will be | |
515 * used during a drag and drop to display the drag under effect on the | |
516 * target widget. | |
517 * | |
518 * @return the drop effect that is registered for this DropTarget | |
519 * | |
520 * @since 3.3 | |
521 */ | |
522 public DropTargetEffect getDropTargetEffect() { | |
523 return dropEffect; | |
524 } | |
525 | |
526 int getOperationFromKeyState(int grfKeyState) { | |
527 bool ctrl = (grfKeyState & OS.MK_CONTROL) !is 0; | |
528 bool shift = (grfKeyState & OS.MK_SHIFT) !is 0; | |
529 bool alt = (grfKeyState & OS.MK_ALT) !is 0; | |
530 if (alt) { | |
531 if (ctrl || shift) return DND.DROP_DEFAULT; | |
532 return DND.DROP_LINK; | |
533 } | |
534 if (ctrl && shift) return DND.DROP_LINK; | |
535 if (ctrl)return DND.DROP_COPY; | |
536 if (shift)return DND.DROP_MOVE; | |
537 return DND.DROP_DEFAULT; | |
538 } | |
539 | |
540 /** | |
541 * Returns a list of the data types that can be transferred to this DropTarget. | |
542 * | |
543 * @return a list of the data types that can be transferred to this DropTarget | |
544 */ | |
545 public Transfer[] getTransfer() { | |
546 return transferAgents; | |
547 } | |
548 | |
549 void onDispose () { | |
550 if (control is null) return; | |
551 | |
552 COM.RevokeDragDrop(control.handle); | |
553 | |
554 if (controlListener !is null) | |
555 control.removeListener(SWT.Dispose, controlListener); | |
556 controlListener = null; | |
557 control.setData(DND.DROP_TARGET_KEY, null); | |
558 transferAgents = null; | |
559 control = null; | |
560 | |
561 COM.CoLockObjectExternal(iDropTarget, false, true); | |
562 | |
563 this.Release(); | |
564 | |
565 COM.CoFreeUnusedLibraries(); | |
566 } | |
567 | |
568 int opToOs(int operation) { | |
569 int osOperation = 0; | |
570 if ((operation & DND.DROP_COPY) !is 0){ | |
571 osOperation |= COM.DROPEFFECT_COPY; | |
572 } | |
573 if ((operation & DND.DROP_LINK) !is 0) { | |
574 osOperation |= COM.DROPEFFECT_LINK; | |
575 } | |
576 if ((operation & DND.DROP_MOVE) !is 0) { | |
577 osOperation |= COM.DROPEFFECT_MOVE; | |
578 } | |
579 return osOperation; | |
580 } | |
581 | |
582 int osToOp(int osOperation){ | |
583 int operation = 0; | |
584 if ((osOperation & COM.DROPEFFECT_COPY) !is 0){ | |
585 operation |= DND.DROP_COPY; | |
586 } | |
587 if ((osOperation & COM.DROPEFFECT_LINK) !is 0) { | |
588 operation |= DND.DROP_LINK; | |
589 } | |
590 if ((osOperation & COM.DROPEFFECT_MOVE) !is 0) { | |
591 operation |= DND.DROP_MOVE; | |
592 } | |
593 return operation; | |
594 } | |
595 | |
596 /* QueryInterface([in] iid, [out] ppvObject) | |
597 * Ownership of ppvObject transfers from callee to caller so reference count on ppvObject | |
598 * must be incremented before returning. Caller is responsible for releasing ppvObject. | |
599 */ | |
600 HRESULT QueryInterface(REFIID riid, void ** ppvObject) { | |
601 | |
602 if (riid is null || ppvObject is null) | |
603 return COM.E_INVALIDARG; | |
604 if (COM.IsEqualGUID(riid, &COM.IIDIUnknown) || COM.IsEqualGUID(riid, &COM.IIDIDropTarget)) { | |
605 *ppvObject = cast(void*)cast(IDropTarget) iDropTarget; | |
606 AddRef(); | |
607 return COM.S_OK; | |
608 } | |
609 | |
610 *ppvObject = null; | |
611 return COM.E_NOINTERFACE; | |
612 } | |
613 | |
614 ULONG Release() { | |
615 refCount--; | |
616 | |
617 if (refCount is 0) { | |
618 disposeCOMInterfaces(); | |
619 COM.CoFreeUnusedLibraries(); | |
620 } | |
621 | |
622 return refCount; | |
623 } | |
624 | |
625 void refresh() { | |
626 if (control is null || control.isDisposed()) return; | |
627 auto handle = control.handle; | |
628 RECT lpRect; | |
629 if (OS.GetUpdateRect(handle, &lpRect, false)) { | |
630 OS.ImageList_DragShowNolock(false); | |
631 OS.RedrawWindow(handle, &lpRect, null, OS.RDW_UPDATENOW | OS.RDW_INVALIDATE); | |
632 OS.ImageList_DragShowNolock(true); | |
633 } | |
634 } | |
635 | |
636 /** | |
637 * Removes the listener from the collection of listeners who will | |
638 * be notified when a drag and drop operation is in progress. | |
639 * | |
640 * @param listener the listener which should no longer be notified | |
641 * | |
642 * @exception IllegalArgumentException <ul> | |
643 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> | |
644 * </ul> | |
645 * @exception SWTException <ul> | |
646 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
647 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
648 * </ul> | |
649 * | |
650 * @see DropTargetListener | |
651 * @see #addDropListener | |
652 * @see #getDropListeners | |
653 */ | |
654 public void removeDropListener(DropTargetListener listener) { | |
655 if (listener is null) DND.error (SWT.ERROR_NULL_ARGUMENT); | |
656 removeListener (DND.DragEnter, listener); | |
657 removeListener (DND.DragLeave, listener); | |
658 removeListener (DND.DragOver, listener); | |
659 removeListener (DND.DragOperationChanged, listener); | |
660 removeListener (DND.Drop, listener); | |
661 removeListener (DND.DropAccept, listener); | |
662 } | |
663 | |
664 /** | |
665 * Specifies the drop effect for this DropTarget. This drop effect will be | |
666 * used during a drag and drop to display the drag under effect on the | |
667 * target widget. | |
668 * | |
669 * @param effect the drop effect that is registered for this DropTarget | |
670 * | |
671 * @since 3.3 | |
672 */ | |
673 public void setDropTargetEffect(DropTargetEffect effect) { | |
674 dropEffect = effect; | |
675 } | |
676 | |
677 bool setEventData(DNDEvent event, IDataObject pDataObject, int grfKeyState, POINTL pt, DWORD* pdwEffect) { | |
678 if (pDataObject is null || pdwEffect is null) return false; | |
679 | |
680 // get allowed operations | |
681 int style = getStyle(); | |
682 int[1] operations; | |
683 OS.MoveMemory(operations.ptr, pdwEffect, 4); | |
684 operations[0] = osToOp(operations[0]) & style; | |
685 if (operations[0] is DND.DROP_NONE) return false; | |
686 | |
687 // get current operation | |
688 int operation = getOperationFromKeyState(grfKeyState); | |
689 keyOperation = operation; | |
690 if (operation is DND.DROP_DEFAULT) { | |
691 if ((style & DND.DROP_DEFAULT) is 0) { | |
692 operation = (operations[0] & DND.DROP_MOVE) !is 0 ? DND.DROP_MOVE : DND.DROP_NONE; | |
693 } | |
694 } else { | |
695 if ((operation & operations[0]) is 0) operation = DND.DROP_NONE; | |
696 } | |
697 | |
698 // Get allowed transfer types | |
699 TransferData[] dataTypes = new TransferData[0]; | |
700 IDataObject dataObject = pDataObject; | |
701 dataObject.AddRef(); | |
702 try { | |
703 IEnumFORMATETC[1] address; | |
704 if (dataObject.EnumFormatEtc(COM.DATADIR_GET, address.ptr) !is COM.S_OK) { | |
705 return false; | |
706 } | |
707 IEnumFORMATETC enumFormatetc = address[0]; | |
708 try { | |
709 // Loop over enumerator and save any types that match what we are looking for | |
710 auto rgelt = cast(FORMATETC*) OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, FORMATETC.sizeof); | |
711 try { | |
712 uint[1] pceltFetched; | |
713 enumFormatetc.Reset(); | |
714 while (enumFormatetc.Next(1, rgelt, pceltFetched.ptr) is COM.S_OK && pceltFetched[0] is 1) { | |
715 TransferData transferData = new TransferData(); | |
716 transferData.formatetc = new FORMATETC(); | |
717 COM.MoveMemory(transferData.formatetc, rgelt, FORMATETC.sizeof); | |
718 transferData.type = transferData.formatetc.cfFormat; | |
719 transferData.pIDataObject = pDataObject; | |
720 for (int i = 0; i < transferAgents.length; i++){ | |
721 Transfer transfer = transferAgents[i]; | |
722 if (transfer !is null && transfer.isSupportedType(transferData)){ | |
723 TransferData[] newDataTypes = new TransferData[dataTypes.length + 1]; | |
724 System.arraycopy(dataTypes, 0, newDataTypes, 0, dataTypes.length); | |
725 newDataTypes[dataTypes.length] = transferData; | |
726 dataTypes = newDataTypes; | |
727 break; | |
728 } | |
729 } | |
730 } | |
731 } finally { | |
732 OS.GlobalFree(rgelt); | |
733 } | |
734 } finally { | |
735 enumFormatetc.Release(); | |
736 } | |
737 } finally { | |
738 dataObject.Release(); | |
739 } | |
740 if (dataTypes.length is 0) return false; | |
741 | |
742 event.widget = this; | |
743 event.x = pt.x; | |
744 event.y = pt.y; | |
745 event.time = OS.GetMessageTime(); | |
746 event.feedback = DND.FEEDBACK_SELECT; | |
747 event.dataTypes = dataTypes; | |
748 event.dataType = dataTypes[0]; | |
749 if (dropEffect !is null) { | |
750 event.item = dropEffect.getItem(pt.x, pt.y); | |
751 } | |
752 event.operations = operations[0]; | |
753 event.detail = operation; | |
754 return true; | |
755 } | |
756 | |
757 /** | |
758 * Specifies the data types that can be transferred to this DropTarget. If data is | |
759 * being dragged that does not match one of these types, the drop target will be notified of | |
760 * the drag and drop operation but the currentDataType will be null and the operation | |
761 * will be DND.NONE. | |
762 * | |
763 * @param transferAgents a list of Transfer objects which define the types of data that can be | |
764 * dropped on this target | |
765 * | |
766 * @exception IllegalArgumentException <ul> | |
767 * <li>ERROR_NULL_ARGUMENT - if transferAgents is null</li> | |
768 * </ul> | |
769 */ | |
770 public void setTransfer(Transfer[] transferAgents){ | |
771 if (transferAgents is null) DND.error(SWT.ERROR_NULL_ARGUMENT); | |
772 this.transferAgents = transferAgents; | |
773 } | |
774 } | |
775 | |
776 class _IDropTargetImpl : IDropTarget { | |
777 | |
778 DropTarget parent; | |
779 this(DropTarget p) { parent = p; } | |
780 extern (Windows): | |
781 // interface of IUnknown | |
782 HRESULT QueryInterface(REFIID riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); } | |
783 ULONG AddRef() { return parent.AddRef(); } | |
784 ULONG Release() { return parent.Release(); } | |
785 | |
786 HRESULT DragEnter( IDataObject pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect ) { | |
787 return parent.DragEnter(pDataObj, grfKeyState, pt, pdwEffect); | |
788 } | |
789 HRESULT DragOver( DWORD grfKeyState, POINTL pt, DWORD *pdwEffect ) { | |
790 return parent.DragOver(grfKeyState, pt, pdwEffect); | |
791 } | |
792 HRESULT DragLeave(){ return parent.DragLeave(); } | |
793 HRESULT Drop(IDataObject pDataObj,DWORD grfKeyState,POINTL pt,DWORD *pdwEffect){ | |
794 return parent.Drop(pDataObj, grfKeyState, pt, pdwEffect); | |
795 } | |
796 } | |
797 | |
798 |