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