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