Mercurial > projects > dwt-linux
annotate dwt/dnd/DropTarget.d @ 259:c0d810de7093
Update SWT 3.4M7 to 3.4
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sun, 29 Jun 2008 14:33:38 +0200 |
parents | ce446666f5a2 |
children |
rev | line source |
---|---|
115
52b32f5cb1e0
many file checked for switch default
Frank Benoit <benoit@tionex.de>
parents:
108
diff
changeset
|
1 /******************************************************************************* |
259 | 2 * Copyright (c) 2000, 2008 IBM Corporation and others. |
92 | 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 | |
108 | 10 * Port to the D programming language: |
11 * Frank Benoit <benoit@tionex.de> | |
92 | 12 *******************************************************************************/ |
13 module dwt.dnd.DropTarget; | |
14 | |
15 | |
16 | |
17 import dwt.DWT; | |
18 import dwt.DWTError; | |
19 import dwt.DWTException; | |
20 import dwt.graphics.Point; | |
21 import dwt.internal.gtk.OS; | |
240 | 22 import dwt.widgets.Combo; |
92 | 23 import dwt.widgets.Control; |
24 import dwt.widgets.Display; | |
25 import dwt.widgets.Event; | |
26 import dwt.widgets.Listener; | |
27 import dwt.widgets.Table; | |
28 import dwt.widgets.Tree; | |
29 import dwt.widgets.Widget; | |
30 import dwt.dnd.DND; | |
31 import dwt.dnd.Transfer; | |
32 import dwt.dnd.DropTargetEffect; | |
33 import dwt.dnd.DNDEvent; | |
34 import dwt.dnd.DNDListener; | |
35 import dwt.dnd.TransferData; | |
36 import dwt.dnd.DropTargetListener; | |
37 import dwt.dnd.TableDropTargetEffect; | |
38 import dwt.dnd.TreeDropTargetEffect; | |
200
08789b28bdf3
import dwt.dwthelper.utils now explicit
Frank Benoit <benoit@tionex.de>
parents:
192
diff
changeset
|
39 import dwt.dwthelper.utils; |
92 | 40 |
41 import dwt.dwthelper.Runnable; | |
42 import tango.core.Thread; | |
43 static import tango.stdc.string; | |
44 | |
45 /** | |
46 * | |
47 * Class <code>DropTarget</code> defines the target object for a drag and drop transfer. | |
48 * | |
49 * IMPORTANT: This class is <em>not</em> intended to be subclassed. | |
50 * | |
51 * <p>This class identifies the <code>Control</code> over which the user must position the cursor | |
52 * in order to drop the data being transferred. It also specifies what data types can be dropped on | |
53 * this control and what operations can be performed. You may have several DropTragets in an | |
54 * application but there can only be a one to one mapping between a <code>Control</code> and a <code>DropTarget</code>. | |
55 * The DropTarget can receive data from within the same application or from other applications | |
56 * (such as text dragged from a text editor like Word).</p> | |
57 * | |
58 * <code><pre> | |
59 * int operations = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK; | |
60 * Transfer[] types = new Transfer[] {TextTransfer.getInstance()}; | |
61 * DropTarget target = new DropTarget(label, operations); | |
62 * target.setTransfer(types); | |
63 * </code></pre> | |
64 * | |
65 * <p>The application is notified of data being dragged over this control and of when a drop occurs by | |
66 * implementing the interface <code>DropTargetListener</code> which uses the class | |
67 * <code>DropTargetEvent</code>. The application can modify the type of drag being performed | |
68 * on this Control at any stage of the drag by modifying the <code>event.detail</code> field or the | |
69 * <code>event.currentDataType</code> field. When the data is dropped, it is the responsibility of | |
70 * the application to copy this data for its own purposes. | |
71 * | |
72 * <code><pre> | |
73 * target.addDropListener (new DropTargetListener() { | |
74 * public void dragEnter(DropTargetEvent event) {}; | |
75 * public void dragOver(DropTargetEvent event) {}; | |
76 * public void dragLeave(DropTargetEvent event) {}; | |
77 * public void dragOperationChanged(DropTargetEvent event) {}; | |
78 * public void dropAccept(DropTargetEvent event) {} | |
79 * public void drop(DropTargetEvent event) { | |
80 * // A drop has occurred, copy over the data | |
81 * if (event.data is null) { // no data to copy, indicate failure in event.detail | |
82 * event.detail = DND.DROP_NONE; | |
83 * return; | |
84 * } | |
85 * label.setText ((String) event.data); // data copied to label text | |
86 * } | |
87 * }); | |
88 * </pre></code> | |
89 * | |
90 * <dl> | |
91 * <dt><b>Styles</b></dt> <dd>DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK</dd> | |
92 * <dt><b>Events</b></dt> <dd>DND.DragEnter, DND.DragLeave, DND.DragOver, DND.DragOperationChanged, | |
93 * DND.DropAccept, DND.Drop </dd> | |
94 * </dl> | |
259 | 95 * |
96 * @see <a href="http://www.eclipse.org/swt/snippets/#dnd">Drag and Drop snippets</a> | |
97 * @see <a href="http://www.eclipse.org/swt/examples.php">DWT Example: DNDExample</a> | |
98 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> | |
92 | 99 */ |
100 public class DropTarget : Widget { | |
101 | |
102 Control control; | |
103 Listener controlListener; | |
104 Transfer[] transferAgents; | |
105 DropTargetEffect dropEffect; | |
106 | |
107 // Track application selections | |
108 TransferData selectedDataType; | |
109 int selectedOperation; | |
110 | |
111 // workaround - There is no event for "operation changed" so track operation based on key state | |
112 int keyOperation = -1; | |
113 | |
114 // workaround - Simulate events when the mouse is not moving | |
115 long dragOverStart; | |
116 Runnable dragOverHeartbeat; | |
117 DNDEvent dragOverEvent; | |
118 | |
119 int drag_motion_handler; | |
120 int drag_leave_handler; | |
121 int drag_data_received_handler; | |
122 int drag_drop_handler; | |
123 | |
238 | 124 static const String DEFAULT_DROP_TARGET_EFFECT = "DEFAULT_DROP_TARGET_EFFECT"; //$NON-NLS-1$ |
92 | 125 static const int DRAGOVER_HYSTERESIS = 50; |
126 | |
127 // static Callback Drag_Motion; | |
128 // static Callback Drag_Leave; | |
129 // static Callback Drag_Data_Received; | |
130 // static Callback Drag_Drop; | |
131 // | |
132 // static this(){ | |
133 // Drag_Motion = new Callback(DropTarget.class, "Drag_Motion", 5); //$NON-NLS-1$ | |
134 // if (Drag_Motion.getAddress() is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS); | |
135 // Drag_Leave = new Callback(DropTarget.class, "Drag_Leave", 3); //$NON-NLS-1$ | |
136 // if (Drag_Leave.getAddress() is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS); | |
137 // Drag_Data_Received = new Callback(DropTarget.class, "Drag_Data_Received", 7); //$NON-NLS-1$ | |
138 // if (Drag_Data_Received.getAddress() is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS); | |
139 // Drag_Drop = new Callback(DropTarget.class, "Drag_Drop", 5); //$NON-NLS-1$ | |
140 // if (Drag_Drop.getAddress() is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS); | |
141 // } | |
142 | |
143 /** | |
144 * Creates a new <code>DropTarget</code> to allow data to be dropped on the specified | |
145 * <code>Control</code>. | |
146 * Creating an instance of a DropTarget may cause system resources to be allocated | |
147 * depending on the platform. It is therefore mandatory that the DropTarget instance | |
148 * be disposed when no longer required. | |
149 * | |
150 * @param control the <code>Control</code> over which the user positions the cursor to drop the data | |
151 * @param style the bitwise OR'ing of allowed operations; this may be a combination of any of | |
152 * DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK | |
153 * | |
154 * @exception DWTException <ul> | |
155 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> | |
156 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> | |
157 * </ul> | |
158 * @exception DWTError <ul> | |
159 * <li>ERROR_CANNOT_INIT_DROP - unable to initiate drop target; this will occur if more than one | |
160 * drop target is created for a control or if the operating system will not allow the creation | |
161 * of the drop target</li> | |
162 * </ul> | |
163 * | |
164 * <p>NOTE: ERROR_CANNOT_INIT_DROP should be an DWTException, since it is a | |
165 * recoverable error, but can not be changed due to backward compatibility.</p> | |
166 * | |
167 * @see Widget#dispose | |
168 * @see DropTarget#checkSubclass | |
169 * @see DND#DROP_NONE | |
170 * @see DND#DROP_COPY | |
171 * @see DND#DROP_MOVE | |
172 * @see DND#DROP_LINK | |
173 */ | |
174 public this(Control control, int style) { | |
175 super(control, checkStyle(style)); | |
176 this.control = control; | |
177 // if (Drag_Motion is null || Drag_Leave is null || Drag_Data_Received is null || Drag_Drop is null) { | |
178 // DND.error(DND.ERROR_CANNOT_INIT_DROP); | |
179 // } | |
240 | 180 if (control.getData(DND.DROP_TARGET_KEY) !is null) { |
92 | 181 DND.error(DND.ERROR_CANNOT_INIT_DROP); |
182 } | |
240 | 183 control.setData(DND.DROP_TARGET_KEY, this); |
92 | 184 |
185 drag_motion_handler = OS.g_signal_connect(control.handle, OS.drag_motion.ptr, cast(GCallback)&Drag_Motion, null); | |
186 drag_leave_handler = OS.g_signal_connect(control.handle, OS.drag_leave.ptr, cast(GCallback)&Drag_Leave, null); | |
187 drag_data_received_handler = OS.g_signal_connect(control.handle, OS.drag_data_received.ptr, cast(GCallback)&Drag_Data_Received, null); | |
188 drag_drop_handler = OS.g_signal_connect(control.handle, OS.drag_drop.ptr, cast(GCallback)&Drag_Drop, null); | |
189 | |
190 // Dispose listeners | |
191 controlListener = new class() Listener{ | |
192 public void handleEvent(Event event){ | |
193 if (!this.outer.isDisposed()){ | |
194 this.outer.dispose(); | |
195 } | |
196 } | |
197 }; | |
198 control.addListener(DWT.Dispose, controlListener); | |
199 | |
200 this.addListener(DWT.Dispose, new class() Listener { | |
201 public void handleEvent(Event event){ | |
202 onDispose(); | |
203 } | |
204 }); | |
205 | |
206 Object effect = control.getData(DEFAULT_DROP_TARGET_EFFECT); | |
207 if ( auto de = cast(DropTargetEffect)effect ) { | |
208 dropEffect = de; | |
209 } else if ( auto table = cast(Table)control ) { | |
210 dropEffect = new TableDropTargetEffect(table); | |
211 } else if ( auto tree = cast(Tree) control ) { | |
212 dropEffect = new TreeDropTargetEffect(tree); | |
213 } | |
214 | |
215 dragOverHeartbeat = new class() Runnable { | |
216 public void run() { | |
217 Control control = this.outer.control; | |
218 if (control is null || control.isDisposed() || dragOverStart is 0) return; | |
219 long time = System.currentTimeMillis(); | |
220 int delay = DRAGOVER_HYSTERESIS; | |
221 if (time < dragOverStart) { | |
222 delay = cast(int)(dragOverStart - time); | |
223 } else { | |
224 dragOverEvent.time += DRAGOVER_HYSTERESIS; | |
225 int allowedOperations = dragOverEvent.operations; | |
226 TransferData[] allowedTypes = dragOverEvent.dataTypes; | |
227 //pass a copy of data types in to listeners in case application modifies it | |
228 TransferData[] dataTypes = new TransferData[allowedTypes.length]; | |
229 System.arraycopy(allowedTypes, 0, dataTypes, 0, dataTypes.length); | |
230 | |
231 DNDEvent event = new DNDEvent(); | |
232 event.widget = dragOverEvent.widget; | |
233 event.x = dragOverEvent.x; | |
234 event.y = dragOverEvent.y; | |
235 event.time = dragOverEvent.time; | |
236 event.feedback = DND.FEEDBACK_SELECT; | |
237 event.dataTypes = dataTypes; | |
238 event.dataType = selectedDataType; | |
239 event.operations = dragOverEvent.operations; | |
240 event.detail = selectedOperation; | |
241 if (dropEffect !is null) { | |
242 event.item = dropEffect.getItem(dragOverEvent.x, dragOverEvent.y); | |
243 } | |
244 selectedDataType = null; | |
245 selectedOperation = DND.DROP_NONE; | |
246 notifyListeners(DND.DragOver, event); | |
247 if (event.dataType !is null) { | |
248 for (int i = 0; i < allowedTypes.length; i++) { | |
249 if (allowedTypes[i].type is event.dataType.type) { | |
250 selectedDataType = event.dataType; | |
251 break; | |
252 } | |
253 } | |
254 } | |
255 if (selectedDataType !is null && (event.detail & allowedOperations) !is 0) { | |
256 selectedOperation = event.detail; | |
257 } | |
258 } | |
259 control = this.outer.control; | |
260 if (control is null || control.isDisposed()) return; | |
261 control.getDisplay().timerExec(delay, dragOverHeartbeat); | |
262 } | |
263 }; | |
264 } | |
265 | |
266 static int checkStyle (int style) { | |
267 if (style is DWT.NONE) return DND.DROP_MOVE; | |
268 return style; | |
269 } | |
270 | |
271 private static extern(C) void Drag_Data_Received ( | |
272 GtkWidget *widget, | |
273 GdkDragContext *context, | |
274 int x, | |
275 int y, | |
276 GtkSelectionData *data, | |
277 uint info, | |
278 uint time, | |
279 void* user_data) | |
280 { | |
281 DropTarget target = FindDropTarget(widget); | |
282 if (target is null) return; | |
283 target.drag_data_received (widget, context, cast(int)/*64*/x, cast(int)/*64*/y, data, cast(int)/*64*/info, cast(int)/*64*/time); | |
284 } | |
285 | |
286 private static extern(C) int Drag_Drop( | |
287 GtkWidget *widget, | |
288 GdkDragContext *context, | |
289 int x, | |
290 int y, | |
291 uint time, | |
292 void* user_data) | |
293 { | |
294 DropTarget target = FindDropTarget(widget); | |
295 if (target is null) return 0; | |
296 return target.drag_drop (widget, context, cast(int)/*64*/x, cast(int)/*64*/y, cast(int)/*64*/time) ? 1 : 0; | |
297 } | |
298 | |
299 private static extern(C) void Drag_Leave ( | |
300 GtkWidget *widget, | |
301 GdkDragContext *context, | |
302 uint time, | |
303 void* user_data) | |
304 { | |
305 DropTarget target = FindDropTarget(widget); | |
306 if (target is null) return; | |
307 target.drag_leave (widget, context, cast(int)/*64*/time); | |
308 } | |
309 | |
310 private static extern(C) int Drag_Motion ( | |
311 GtkWidget *widget, | |
312 GdkDragContext *context, | |
313 int x, | |
314 int y, | |
315 uint time, | |
316 void* user_data) | |
317 { | |
318 DropTarget target = FindDropTarget(widget); | |
319 if (target is null) return 0; | |
320 return target.drag_motion (widget, context, cast(int)/*64*/x, cast(int)/*64*/y, cast(int)/*64*/time) ? 1 : 0; | |
321 } | |
322 | |
323 static DropTarget FindDropTarget(GtkWidget* handle) { | |
324 Display display = Display.findDisplay(Thread.getThis()); | |
325 if (display is null || display.isDisposed()) return null; | |
326 Widget widget = display.findWidget(handle); | |
327 if (widget is null) return null; | |
240 | 328 return cast(DropTarget)widget.getData(DND.DROP_TARGET_KEY); |
92 | 329 } |
330 | |
331 /** | |
332 * Adds the listener to the collection of listeners who will | |
333 * be notified when a drag and drop operation is in progress, by sending | |
334 * it one of the messages defined in the <code>DropTargetListener</code> | |
335 * interface. | |
336 * | |
337 * <p><ul> | |
338 * <li><code>dragEnter</code> is called when the cursor has entered the drop target boundaries | |
339 * <li><code>dragLeave</code> is called when the cursor has left the drop target boundaries and just before | |
340 * the drop occurs or is cancelled. | |
341 * <li><code>dragOperationChanged</code> is called when the operation being performed has changed | |
342 * (usually due to the user changing the selected modifier key(s) while dragging) | |
343 * <li><code>dragOver</code> is called when the cursor is moving over the drop target | |
344 * <li><code>dropAccept</code> is called just before the drop is performed. The drop target is given | |
345 * the chance to change the nature of the drop or veto the drop by setting the <code>event.detail</code> field | |
346 * <li><code>drop</code> is called when the data is being dropped | |
347 * </ul></p> | |
348 * | |
349 * @param listener the listener which should be notified | |
350 * | |
351 * @exception IllegalArgumentException <ul> | |
352 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> | |
353 * </ul> | |
354 * @exception DWTException <ul> | |
355 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
356 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
357 * </ul> | |
358 * | |
359 * @see DropTargetListener | |
259 | 360 * @see #getDropListeners |
92 | 361 * @see #removeDropListener |
362 * @see DropTargetEvent | |
363 */ | |
364 public void addDropListener(DropTargetListener listener) { | |
365 if (listener is null) DND.error (DWT.ERROR_NULL_ARGUMENT); | |
366 DNDListener typedListener = new DNDListener (listener); | |
367 typedListener.dndWidget = this; | |
368 addListener (DND.DragEnter, typedListener); | |
369 addListener (DND.DragLeave, typedListener); | |
370 addListener (DND.DragOver, typedListener); | |
371 addListener (DND.DragOperationChanged, typedListener); | |
372 addListener (DND.Drop, typedListener); | |
373 addListener (DND.DropAccept, typedListener); | |
374 } | |
375 | |
152
17f8449522fd
overloads second walkthrough
Frank Benoit <benoit@tionex.de>
parents:
115
diff
changeset
|
376 protected override void checkSubclass () { |
238 | 377 String name = this.classinfo.name; |
378 String validName = DropTarget.classinfo.name; | |
92 | 379 if ( validName !=/*eq*/ name ) { |
380 DND.error (DWT.ERROR_INVALID_SUBCLASS); | |
381 } | |
382 } | |
383 | |
384 void drag_data_received ( | |
385 GtkWidget *widget, | |
386 GdkDragContext *context, | |
387 int x, | |
388 int y, | |
389 GtkSelectionData *data, | |
390 uint info, | |
391 uint time ) | |
392 { | |
393 DNDEvent event = new DNDEvent(); | |
394 if (data is null || !setEventData(context, x, y, time, event)) { | |
395 keyOperation = -1; | |
396 return; | |
397 } | |
398 keyOperation = -1; | |
399 | |
400 int allowedOperations = event.operations; | |
401 | |
402 // Get data in a Java format | |
403 Object object = null; | |
404 TransferData transferData = new TransferData(); | |
405 if (data.data !is null) { | |
406 transferData.type = data.type; | |
407 transferData.length = data.length; | |
408 transferData.pValue = data.data; | |
409 transferData.format = data.format; | |
410 for (int i = 0; i < transferAgents.length; i++) { | |
411 Transfer transfer = transferAgents[i]; | |
412 if (transfer !is null && transfer.isSupportedType(transferData)) { | |
413 object = transfer.nativeToJava(transferData); | |
414 break; | |
415 } | |
416 } | |
417 } | |
418 if (object is null) { | |
419 selectedOperation = DND.DROP_NONE; | |
420 } | |
421 | |
422 event.detail = selectedOperation; | |
423 event.dataType = transferData; | |
424 event.data = object; | |
425 selectedOperation = DND.DROP_NONE; | |
426 notifyListeners(DND.Drop, event); | |
427 if ((allowedOperations & event.detail) is event.detail) { | |
428 selectedOperation = event.detail; | |
429 } | |
430 //stop native handler | |
431 OS.g_signal_stop_emission_by_name(widget, OS.drag_data_received.ptr); | |
432 | |
433 //notify source of action taken | |
434 OS.gtk_drag_finish(context, selectedOperation !is DND.DROP_NONE, selectedOperation is DND.DROP_MOVE, time); | |
435 return; | |
436 } | |
437 | |
438 bool drag_drop( | |
439 GtkWidget *widget, | |
440 GdkDragContext *context, | |
441 int x, | |
442 int y, | |
443 uint time) | |
444 { | |
445 DNDEvent event = new DNDEvent(); | |
446 if (!setEventData(context, x, y, time, event)) { | |
447 keyOperation = -1; | |
448 return false; | |
449 } | |
450 keyOperation = -1; | |
451 | |
452 int allowedOperations = event.operations; | |
453 TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length]; | |
454 System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length); | |
455 | |
456 event.dataType = selectedDataType; | |
457 event.detail = selectedOperation; | |
458 selectedDataType = null; | |
459 selectedOperation = DND.DROP_NONE; | |
460 notifyListeners(DND.DropAccept,event); | |
461 if (event.dataType !is null) { | |
462 for (int i = 0; i < allowedDataTypes.length; i++) { | |
463 if (allowedDataTypes[i].type is event.dataType.type) { | |
464 selectedDataType = allowedDataTypes[i]; | |
465 break; | |
466 } | |
467 } | |
468 } | |
469 if (selectedDataType !is null && ((event.detail & allowedOperations) is event.detail)) { | |
470 selectedOperation = event.detail; | |
471 } | |
472 if (selectedOperation is DND.DROP_NONE) { | |
473 // this was not a successful drop | |
474 return false; | |
475 } | |
476 // ask drag source for dropped data | |
477 OS.gtk_drag_get_data(widget, context, selectedDataType.type, time); | |
478 return true; | |
479 } | |
480 | |
481 void drag_leave( | |
482 GtkWidget *widget, | |
483 GdkDragContext *context, | |
484 uint time ) | |
485 { | |
486 updateDragOverHover(0, null); | |
487 | |
488 if (keyOperation is -1) return; | |
489 keyOperation = -1; | |
490 | |
491 DNDEvent event = new DNDEvent(); | |
492 event.widget = this; | |
493 event.time = time; | |
494 event.detail = DND.DROP_NONE; | |
495 notifyListeners(DND.DragLeave, event); | |
496 } | |
497 | |
498 bool drag_motion ( | |
499 GtkWidget *widget, | |
500 GdkDragContext *context, | |
501 int x, | |
502 int y, | |
503 uint time) | |
504 { | |
505 int oldKeyOperation = keyOperation; | |
506 | |
507 if (oldKeyOperation is -1) { //drag enter | |
508 selectedDataType = null; | |
509 selectedOperation = DND.DROP_NONE; | |
510 } | |
511 | |
512 DNDEvent event = new DNDEvent(); | |
513 if (!setEventData(context, x, y, time, event)) { | |
514 keyOperation = -1; | |
515 OS.gdk_drag_status(context, 0, time); | |
516 return false; | |
517 } | |
518 | |
519 int allowedOperations = event.operations; | |
520 TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length]; | |
521 System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length); | |
522 | |
523 if (oldKeyOperation is -1) { | |
524 event.type = DND.DragEnter; | |
525 } else { | |
526 if (keyOperation is oldKeyOperation) { | |
527 event.type = DND.DragOver; | |
528 event.dataType = selectedDataType; | |
529 event.detail = selectedOperation; | |
530 } else { | |
531 event.type = DND.DragOperationChanged; | |
532 event.dataType = selectedDataType; | |
533 } | |
534 } | |
535 updateDragOverHover(DRAGOVER_HYSTERESIS, event); | |
536 selectedDataType = null; | |
537 selectedOperation = DND.DROP_NONE; | |
538 notifyListeners(event.type, event); | |
539 if (event.detail is DND.DROP_DEFAULT) { | |
540 event.detail = (allowedOperations & DND.DROP_MOVE) !is 0 ? DND.DROP_MOVE : DND.DROP_NONE; | |
541 } | |
542 if (event.dataType !is null) { | |
543 for (int i = 0; i < allowedDataTypes.length; i++) { | |
544 if (allowedDataTypes[i].type is event.dataType.type) { | |
545 selectedDataType = allowedDataTypes[i]; | |
546 break; | |
547 } | |
548 } | |
549 } | |
550 if (selectedDataType !is null && (allowedOperations & event.detail) !is 0) { | |
551 selectedOperation = event.detail; | |
552 } | |
553 | |
554 switch (selectedOperation) { | |
555 case DND.DROP_NONE: | |
556 OS.gdk_drag_status(context, 0, time); | |
557 break; | |
558 case DND.DROP_COPY: | |
559 OS.gdk_drag_status(context, OS.GDK_ACTION_COPY, time); | |
560 break; | |
561 case DND.DROP_MOVE: | |
562 OS.gdk_drag_status(context, OS.GDK_ACTION_MOVE, time); | |
563 break; | |
564 case DND.DROP_LINK: | |
565 OS.gdk_drag_status(context, OS.GDK_ACTION_LINK, time); | |
566 break; | |
115
52b32f5cb1e0
many file checked for switch default
Frank Benoit <benoit@tionex.de>
parents:
108
diff
changeset
|
567 default: |
92 | 568 } |
569 | |
570 if (oldKeyOperation is -1) { | |
571 dragOverHeartbeat.run(); | |
572 } | |
573 return true; | |
574 } | |
575 | |
576 /** | |
577 * Returns the Control which is registered for this DropTarget. This is the control over which the | |
578 * user positions the cursor to drop the data. | |
579 * | |
580 * @return the Control which is registered for this DropTarget | |
581 */ | |
582 public Control getControl () { | |
583 return control; | |
584 } | |
585 | |
586 /** | |
240 | 587 * Returns an array of listeners who will be notified when a drag and drop |
588 * operation is in progress, by sending it one of the messages defined in | |
589 * the <code>DropTargetListener</code> interface. | |
590 * | |
259 | 591 * @return the listeners who will be notified when a drag and drop |
592 * operation is in progress | |
593 * | |
240 | 594 * @exception DWTException <ul> |
595 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
596 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
597 * </ul> | |
598 * | |
599 * @see DropTargetListener | |
600 * @see #addDropListener | |
601 * @see #removeDropListener | |
602 * @see DropTargetEvent | |
603 * | |
604 * @since 3.4 | |
605 */ | |
606 public DropTargetListener[] getDropListeners() { | |
607 Listener[] listeners = getListeners(DND.DragEnter); | |
608 int length = listeners.length; | |
609 DropTargetListener[] dropListeners = new DropTargetListener[length]; | |
610 int count = 0; | |
611 for (int i = 0; i < length; i++) { | |
612 Listener listener = listeners[i]; | |
613 if ( auto l = cast(DNDListener)listener ) { | |
614 dropListeners[count] = cast(DropTargetListener) (l.getEventListener()); | |
615 count++; | |
616 } | |
617 } | |
618 if (count is length) return dropListeners; | |
619 DropTargetListener[] result = new DropTargetListener[count]; | |
620 SimpleType!(DropTargetListener).arraycopy(dropListeners, 0, result, 0, count); | |
621 return result; | |
622 } | |
623 | |
624 /** | |
92 | 625 * Returns the drop effect for this DropTarget. This drop effect will be |
626 * used during a drag and drop to display the drag under effect on the | |
627 * target widget. | |
628 * | |
629 * @return the drop effect that is registered for this DropTarget | |
630 * | |
631 * @since 3.3 | |
632 */ | |
633 public DropTargetEffect getDropTargetEffect() { | |
634 return dropEffect; | |
635 } | |
636 | |
637 int getOperationFromKeyState() { | |
638 int state; | |
639 OS.gdk_window_get_pointer(null, null, null, &state); | |
640 bool ctrl = (state & OS.GDK_CONTROL_MASK) !is 0; | |
641 bool shift = (state & OS.GDK_SHIFT_MASK) !is 0; | |
642 if (ctrl && shift) return DND.DROP_LINK; | |
643 if (ctrl)return DND.DROP_COPY; | |
644 if (shift)return DND.DROP_MOVE; | |
645 return DND.DROP_DEFAULT; | |
646 } | |
647 | |
648 /** | |
649 * Returns a list of the data types that can be transferred to this DropTarget. | |
650 * | |
651 * @return a list of the data types that can be transferred to this DropTarget | |
652 */ | |
653 public Transfer[] getTransfer() { | |
654 return transferAgents; | |
655 } | |
656 | |
657 void onDispose(){ | |
658 if (control is null) return; | |
659 OS.g_signal_handler_disconnect(control.handle, drag_motion_handler); | |
660 OS.g_signal_handler_disconnect(control.handle, drag_leave_handler); | |
661 OS.g_signal_handler_disconnect(control.handle, drag_data_received_handler); | |
662 OS.g_signal_handler_disconnect(control.handle, drag_drop_handler); | |
663 if (transferAgents.length !is 0) | |
664 OS.gtk_drag_dest_unset(control.handle); | |
665 transferAgents = null; | |
666 if (controlListener !is null) | |
667 control.removeListener(DWT.Dispose, controlListener); | |
240 | 668 control.setData(DND.DROP_TARGET_KEY, null); |
92 | 669 control = null; |
670 controlListener = null; | |
671 } | |
672 | |
673 int opToOsOp(int operation){ | |
674 int osOperation = 0; | |
675 if ((operation & DND.DROP_COPY) is DND.DROP_COPY) | |
676 osOperation |= OS.GDK_ACTION_COPY; | |
677 if ((operation & DND.DROP_MOVE) is DND.DROP_MOVE) | |
678 osOperation |= OS.GDK_ACTION_MOVE; | |
679 if ((operation & DND.DROP_LINK) is DND.DROP_LINK) | |
680 osOperation |= OS.GDK_ACTION_LINK; | |
681 return osOperation; | |
682 } | |
683 | |
684 int osOpToOp(int osOperation){ | |
685 int operation = DND.DROP_NONE; | |
686 if ((osOperation & OS.GDK_ACTION_COPY) is OS.GDK_ACTION_COPY) | |
687 operation |= DND.DROP_COPY; | |
688 if ((osOperation & OS.GDK_ACTION_MOVE) is OS.GDK_ACTION_MOVE) | |
689 operation |= DND.DROP_MOVE; | |
690 if ((osOperation & OS.GDK_ACTION_LINK) is OS.GDK_ACTION_LINK) | |
691 operation |= DND.DROP_LINK; | |
692 return operation; | |
693 } | |
694 | |
695 /** | |
696 * Removes the listener from the collection of listeners who will | |
697 * be notified when a drag and drop operation is in progress. | |
698 * | |
259 | 699 * @param listener the listener which should no longer be notified |
92 | 700 * |
701 * @exception IllegalArgumentException <ul> | |
702 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> | |
703 * </ul> | |
704 * @exception DWTException <ul> | |
705 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
706 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
707 * </ul> | |
708 * | |
709 * @see DropTargetListener | |
710 * @see #addDropListener | |
259 | 711 * @see #getDropListeners |
92 | 712 */ |
713 public void removeDropListener(DropTargetListener listener) { | |
714 if (listener is null) DND.error (DWT.ERROR_NULL_ARGUMENT); | |
715 removeListener (DND.DragEnter, listener); | |
716 removeListener (DND.DragLeave, listener); | |
717 removeListener (DND.DragOver, listener); | |
718 removeListener (DND.DragOperationChanged, listener); | |
719 removeListener (DND.Drop, listener); | |
720 removeListener (DND.DropAccept, listener); | |
721 } | |
722 | |
723 /** | |
724 * Specifies the data types that can be transferred to this DropTarget. If data is | |
725 * being dragged that does not match one of these types, the drop target will be notified of | |
726 * the drag and drop operation but the currentDataType will be null and the operation | |
727 * will be DND.NONE. | |
728 * | |
729 * @param transferAgents a list of Transfer objects which define the types of data that can be | |
730 * dropped on this target | |
731 * | |
732 * @exception IllegalArgumentException <ul> | |
733 * <li>ERROR_NULL_ARGUMENT - if transferAgents is null</li> | |
734 * </ul> | |
735 */ | |
736 public void setTransfer(Transfer[] transferAgents){ | |
737 if (transferAgents is null) DND.error(DWT.ERROR_NULL_ARGUMENT); | |
738 | |
739 if (this.transferAgents.length !is 0) { | |
740 OS.gtk_drag_dest_unset(control.handle); | |
741 } | |
742 this.transferAgents = transferAgents; | |
743 | |
744 GtkTargetEntry*[] targets; | |
745 for (int i = 0; i < transferAgents.length; i++) { | |
746 Transfer transfer = transferAgents[i]; | |
747 if (transfer !is null) { | |
748 int[] typeIds = transfer.getTypeIds(); | |
238 | 749 String[] typeNames = transfer.getTypeNames(); |
92 | 750 for (int j = 0; j < typeIds.length; j++) { |
751 GtkTargetEntry* entry = new GtkTargetEntry(); | |
752 entry.target = cast(char*)OS.g_malloc(typeNames[j].length +1); | |
753 entry.target[ 0 .. typeNames[j].length ] = typeNames[j]; | |
754 entry.target[ typeNames[j].length ] = '\0'; | |
755 entry.info = typeIds[j]; | |
756 GtkTargetEntry*[] newTargets = new GtkTargetEntry*[targets.length + 1]; | |
757 SimpleType!(GtkTargetEntry*).arraycopy(targets, 0, newTargets, 0, targets.length); | |
758 newTargets[targets.length] = entry; | |
759 targets = newTargets; | |
760 } | |
761 } | |
762 } | |
763 | |
764 auto pTargets = OS.g_malloc(targets.length * GtkTargetEntry.sizeof); | |
765 for (int i = 0; i < targets.length; i++) { | |
766 tango.stdc.string.memmove(pTargets + i*GtkTargetEntry.sizeof, targets[i], GtkTargetEntry.sizeof); | |
767 } | |
768 | |
769 int actions = opToOsOp(getStyle()); | |
240 | 770 if ( auto c = cast(Combo)control ) { |
771 if ((control.getStyle() & DWT.READ_ONLY) is 0) { | |
772 auto entryHandle = OS.gtk_bin_get_child (control.handle); | |
773 if (entryHandle !is null) { | |
774 OS.gtk_drag_dest_unset(entryHandle); | |
775 } | |
776 } | |
777 } | |
92 | 778 OS.gtk_drag_dest_set(control.handle, 0, pTargets, targets.length, actions); |
779 | |
780 for (int i = 0; i < targets.length; i++) { | |
781 OS.g_free(targets[i].target); | |
782 } | |
783 } | |
784 | |
785 /** | |
786 * Specifies the drop effect for this DropTarget. This drop effect will be | |
787 * used during a drag and drop to display the drag under effect on the | |
788 * target widget. | |
789 * | |
790 * @param effect the drop effect that is registered for this DropTarget | |
791 * | |
792 * @since 3.3 | |
793 */ | |
794 public void setDropTargetEffect(DropTargetEffect effect) { | |
795 dropEffect = effect; | |
796 } | |
797 | |
798 bool setEventData(GdkDragContext* dragContext, int x, int y, int time, DNDEvent event) { | |
799 if (dragContext is null) return false; | |
800 if (dragContext.targets is null) return false; | |
801 | |
802 // get allowed operations | |
803 int style = getStyle(); | |
804 int operations = osOpToOp(dragContext.actions) & style; | |
805 if (operations is DND.DROP_NONE) return false; | |
806 | |
807 // get current operation | |
808 int operation = getOperationFromKeyState(); | |
809 keyOperation = operation; | |
810 if (operation is DND.DROP_DEFAULT) { | |
811 if ((style & DND.DROP_DEFAULT) is 0) { | |
812 operation = (operations & DND.DROP_MOVE) !is 0 ? DND.DROP_MOVE : DND.DROP_NONE; | |
813 } | |
814 } else { | |
815 if ((operation & operations) is 0) operation = DND.DROP_NONE; | |
816 } | |
817 | |
818 // Get allowed transfer types | |
819 int length = OS.g_list_length(dragContext.targets); | |
820 TransferData[] dataTypes = new TransferData[0]; | |
821 for (int i = 0; i < length; i++) { | |
822 auto pData = OS.g_list_nth(dragContext.targets, i); | |
823 GtkTargetPair* gtkTargetPair = cast(GtkTargetPair*)pData; | |
824 TransferData data = new TransferData(); | |
825 data.type = gtkTargetPair.target; | |
826 for (int j = 0; j < transferAgents.length; j++) { | |
827 Transfer transfer = transferAgents[j]; | |
828 if (transfer !is null && transfer.isSupportedType(data)) { | |
829 TransferData[] newDataTypes = new TransferData[dataTypes.length + 1]; | |
830 System.arraycopy(dataTypes, 0, newDataTypes, 0, dataTypes.length); | |
831 newDataTypes[dataTypes.length] = data; | |
832 dataTypes = newDataTypes; | |
833 break; | |
834 } | |
835 } | |
836 } | |
837 if (dataTypes.length is 0) return false; | |
838 | |
839 auto window = OS.GTK_WIDGET_WINDOW(control.handle); | |
840 int origin_x, origin_y; | |
841 OS.gdk_window_get_origin(window, &origin_x, &origin_y); | |
842 Point coordinates = new Point(origin_x + x, origin_y + y); | |
843 | |
844 event.widget = this; | |
845 event.x = coordinates.x; | |
846 event.y = coordinates.y; | |
847 event.time = time; | |
848 event.feedback = DND.FEEDBACK_SELECT; | |
849 event.dataTypes = dataTypes; | |
850 event.dataType = dataTypes[0]; | |
851 event.operations = operations; | |
852 event.detail = operation; | |
853 if (dropEffect !is null) { | |
854 event.item = dropEffect.getItem(coordinates.x, coordinates.y); | |
855 } | |
856 return true; | |
857 } | |
858 | |
859 void updateDragOverHover(long delay, DNDEvent event) { | |
860 if (delay is 0) { | |
861 dragOverStart = 0; | |
862 dragOverEvent = null; | |
863 return; | |
864 } | |
865 dragOverStart = System.currentTimeMillis() + delay; | |
866 if (dragOverEvent is null) dragOverEvent = new DNDEvent(); | |
867 dragOverEvent.x = event.x; | |
868 dragOverEvent.y = event.y; | |
869 TransferData[] dataTypes = new TransferData[ event.dataTypes.length]; | |
870 System.arraycopy( event.dataTypes, 0, dataTypes, 0, dataTypes.length); | |
871 dragOverEvent.dataTypes = dataTypes; | |
872 dragOverEvent.operations = event.operations; | |
873 dragOverEvent.time = event.time; | |
874 } | |
875 | |
876 } |