comparison dwt/dnd/DropTarget.d @ 0:380af2bdd8e5

Upload of whole dwt tree
author Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com>
date Sat, 09 Aug 2008 17:00:02 +0200
parents
children 1a8b3cb347e0
comparison
equal deleted inserted replaced
-1:000000000000 0:380af2bdd8e5
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 *******************************************************************************/
11 module dwt.dnd;
12
13
14 import dwt.*;
15 import dwt.widgets.*;
16 import dwt.internal.*;
17 import dwt.internal.carbon.*;
18
19 /**
20 *
21 * Class <code>DropTarget</code> defines the target object for a drag and drop transfer.
22 *
23 * IMPORTANT: This class is <em>not</em> intended to be subclassed.
24 *
25 * <p>This class identifies the <code>Control</code> over which the user must position the cursor
26 * in order to drop the data being transferred. It also specifies what data types can be dropped on
27 * this control and what operations can be performed. You may have several DropTragets in an
28 * application but there can only be a one to one mapping between a <code>Control</code> and a <code>DropTarget</code>.
29 * The DropTarget can receive data from within the same application or from other applications
30 * (such as text dragged from a text editor like Word).</p>
31 *
32 * <code><pre>
33 * int operations = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK;
34 * Transfer[] types = new Transfer[] {TextTransfer.getInstance()};
35 * DropTarget target = new DropTarget(label, operations);
36 * target.setTransfer(types);
37 * </code></pre>
38 *
39 * <p>The application is notified of data being dragged over this control and of when a drop occurs by
40 * implementing the interface <code>DropTargetListener</code> which uses the class
41 * <code>DropTargetEvent</code>. The application can modify the type of drag being performed
42 * on this Control at any stage of the drag by modifying the <code>event.detail</code> field or the
43 * <code>event.currentDataType</code> field. When the data is dropped, it is the responsibility of
44 * the application to copy this data for its own purposes.
45 *
46 * <code><pre>
47 * target.addDropListener (new DropTargetListener() {
48 * public void dragEnter(DropTargetEvent event) {};
49 * public void dragOver(DropTargetEvent event) {};
50 * public void dragLeave(DropTargetEvent event) {};
51 * public void dragOperationChanged(DropTargetEvent event) {};
52 * public void dropAccept(DropTargetEvent event) {}
53 * public void drop(DropTargetEvent event) {
54 * // A drop has occurred, copy over the data
55 * if (event.data is null) { // no data to copy, indicate failure in event.detail
56 * event.detail = DND.DROP_NONE;
57 * return;
58 * }
59 * label.setText ((String) event.data); // data copied to label text
60 * }
61 * });
62 * </pre></code>
63 *
64 * <dl>
65 * <dt><b>Styles</b></dt> <dd>DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK</dd>
66 * <dt><b>Events</b></dt> <dd>DND.DragEnter, DND.DragLeave, DND.DragOver, DND.DragOperationChanged,
67 * DND.DropAccept, DND.Drop </dd>
68 * </dl>
69 */
70 public class DropTarget : Widget {
71
72 Control control;
73 Listener controlListener;
74 Transfer[] transferAgents = new Transfer[0];
75 DropTargetEffect dropEffect;
76 int feedback = DND.FEEDBACK_NONE;
77
78 // Track application selections
79 TransferData selectedDataType;
80 int selectedOperation;
81
82 // workaround - There is no event for "operation changed" so track operation based on key state
83 int keyOperation = -1;
84
85 // workaround - Simulate events when mouse is not moving
86 long dragOverStart;
87 Runnable dragOverHeartbeat;
88 DNDEvent dragOverEvent;
89
90 // workaround - OS events are relative to the application, not the control.
91 // Track which control is the current target to determine when drag and
92 // drop enters or leaves a widget.
93 static DropTarget CurrentDropTarget = null;
94
95 static final String DEFAULT_DROP_TARGET_EFFECT = "DEFAULT_DROP_TARGET_EFFECT"; //$NON-NLS-1$
96 static final int DRAGOVER_HYSTERESIS = 50;
97
98 static Callback DragTrackingHandler;
99 static Callback DragReceiveHandler;
100
101 static {
102 DragTrackingHandler = new Callback(DropTarget.class, "DragTrackingHandler", 4); //$NON-NLS-1$
103 int dragTrackingHandlerAddress = DragTrackingHandler.getAddress();
104 if (dragTrackingHandlerAddress is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS);
105 DragReceiveHandler = new Callback(DropTarget.class, "DragReceiveHandler", 3); //$NON-NLS-1$
106 int dragReceiveHandlerAddress = DragReceiveHandler.getAddress();
107 if (dragReceiveHandlerAddress is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS);
108 OS.InstallTrackingHandler(dragTrackingHandlerAddress, 0, null);
109 OS.InstallReceiveHandler(dragReceiveHandlerAddress, 0, null);
110 }
111
112 /**
113 * Creates a new <code>DropTarget</code> to allow data to be dropped on the specified
114 * <code>Control</code>.
115 * Creating an instance of a DropTarget may cause system resources to be allocated
116 * depending on the platform. It is therefore mandatory that the DropTarget instance
117 * be disposed when no longer required.
118 *
119 * @param control the <code>Control</code> over which the user positions the cursor to drop the data
120 * @param style the bitwise OR'ing of allowed operations; this may be a combination of any of
121 * DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK
122 *
123 * @exception DWTException <ul>
124 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
125 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
126 * </ul>
127 * @exception DWTError <ul>
128 * <li>ERROR_CANNOT_INIT_DROP - unable to initiate drop target; this will occur if more than one
129 * drop target is created for a control or if the operating system will not allow the creation
130 * of the drop target</li>
131 * </ul>
132 *
133 * <p>NOTE: ERROR_CANNOT_INIT_DROP should be an DWTException, since it is a
134 * recoverable error, but can not be changed due to backward compatibility.</p>
135 *
136 * @see Widget#dispose
137 * @see DropTarget#checkSubclass
138 * @see DND#DROP_NONE
139 * @see DND#DROP_COPY
140 * @see DND#DROP_MOVE
141 * @see DND#DROP_LINK
142 */
143 public DropTarget(Control control, int style) {
144 super(control, checkStyle(style));
145 this.control = control;
146 if (DragTrackingHandler is null || DragTrackingHandler is null) {
147 DND.error(DND.ERROR_CANNOT_INIT_DROP);
148 }
149 if (control.getData(DND.DROP_TARGET_KEY) !is null) {
150 DND.error(DND.ERROR_CANNOT_INIT_DROP);
151 }
152 control.setData(DND.DROP_TARGET_KEY, this);
153
154 controlListener = new Listener () {
155 public void handleEvent (Event event) {
156 if (!DropTarget.this.isDisposed()) {
157 DropTarget.this.dispose();
158 }
159 }
160 };
161 control.addListener (DWT.Dispose, controlListener);
162
163 this.addListener(DWT.Dispose, new Listener() {
164 public void handleEvent (Event event) {
165 onDispose();
166 }
167 });
168
169 Object effect = control.getData(DEFAULT_DROP_TARGET_EFFECT);
170 if (effect instanceof DropTargetEffect) {
171 dropEffect = (DropTargetEffect) effect;
172 } else if (control instanceof Table) {
173 dropEffect = new TableDropTargetEffect((Table) control);
174 } else if (control instanceof Tree) {
175 dropEffect = new TreeDropTargetEffect((Tree) control);
176 }
177
178 dragOverHeartbeat = new Runnable() {
179 public void run() {
180 Control control = DropTarget.this.control;
181 if (control is null || control.isDisposed() || dragOverStart is 0) return;
182 long time = System.currentTimeMillis();
183 int delay = DRAGOVER_HYSTERESIS;
184 if (time < dragOverStart) {
185 delay = (int)(dragOverStart - time);
186 } else {
187 int allowedOperations = dragOverEvent.operations;
188 TransferData[] allowedTypes = dragOverEvent.dataTypes;
189 //pass a copy of data types in to listeners in case application modifies it
190 TransferData[] dataTypes = new TransferData[allowedTypes.length];
191 System.arraycopy(allowedTypes, 0, dataTypes, 0, dataTypes.length);
192
193 DNDEvent event = new DNDEvent();
194 event.widget = dragOverEvent.widget;
195 event.x = dragOverEvent.x;
196 event.y = dragOverEvent.y;
197 event.time = (int)time;
198 event.feedback = DND.FEEDBACK_SELECT;
199 event.dataTypes = dataTypes;
200 event.dataType = selectedDataType;
201 event.operations = dragOverEvent.operations;
202 event.detail = selectedOperation;
203 if (dropEffect !is null) {
204 event.item = dropEffect.getItem(event.x, event.y);
205 }
206 selectedDataType = null;
207 selectedOperation = DND.DROP_NONE;
208 notifyListeners(DND.DragOver, event);
209 if (event.dataType !is null) {
210 for (int i = 0; i < allowedTypes.length; i++) {
211 if (allowedTypes[i].type is event.dataType.type) {
212 selectedDataType = event.dataType;
213 break;
214 }
215 }
216 }
217 if (selectedDataType !is null && (event.detail & allowedOperations) !is 0) {
218 selectedOperation = event.detail;
219 }
220 }
221 control = DropTarget.this.control;
222 if (control is null || control.isDisposed()) return;
223 control.getDisplay().timerExec(delay, dragOverHeartbeat);
224 }
225 };
226 }
227
228 static int checkStyle (int style) {
229 if (style is DWT.NONE) return DND.DROP_MOVE;
230 return style;
231 }
232
233 static int DragReceiveHandler(int theWindow, int handlerRefCon, int theDrag) {
234 DropTarget target = FindDropTarget(theWindow, theDrag);
235 if (target is null) return OS.noErr;
236 return target.dragReceiveHandler(theWindow, handlerRefCon, theDrag);
237 }
238
239 static int DragTrackingHandler(int message, int theWindow, int handlerRefCon, int theDrag) {
240 if (message is OS.kDragTrackingLeaveHandler || message is OS.kDragTrackingEnterHandler) {
241 CurrentDropTarget = null;
242 return OS.noErr;
243 }
244 DropTarget target = FindDropTarget(theWindow, theDrag);
245 if (CurrentDropTarget !is null) {
246 if (target is null || CurrentDropTarget.control.handle !is target.control.handle) {
247 CurrentDropTarget.dragTrackingHandler(OS.kDragTrackingLeaveWindow, theWindow, handlerRefCon, theDrag);
248 CurrentDropTarget = target;
249 message = OS.kDragTrackingEnterWindow;
250 }
251 } else {
252 CurrentDropTarget = target;
253 message = OS.kDragTrackingEnterWindow;
254 }
255 if (target is null) return OS.noErr;
256 return target.dragTrackingHandler(message, theWindow, handlerRefCon, theDrag);
257 }
258
259 static DropTarget FindDropTarget(int theWindow, int theDrag) {
260 Display display = Display.findDisplay(Thread.currentThread());
261 if (display is null || display.isDisposed()) return null;
262 Point mouse = new Point();
263 OS.GetDragMouse(theDrag, mouse, null);
264 int[] theRoot = new int[1];
265 OS.GetRootControl(theWindow, theRoot);
266 int[] theControl = new int[1];
267 Rect rect = new Rect();
268 OS.GetWindowBounds (theWindow, (short) OS.kWindowContentRgn, rect);
269 CGPoint inPoint = new CGPoint();
270 inPoint.x = mouse.h - rect.left;
271 inPoint.y = mouse.v - rect.top;
272 OS.HIViewGetSubviewHit(theRoot[0], inPoint, true, theControl);
273 if (!OS.IsControlEnabled(theControl[0])) return null;
274 Widget widget = display.findWidget(theControl[0]);
275 if (widget is null) return null;
276 return (DropTarget)widget.getData(DND.DROP_TARGET_KEY);
277 }
278 /**
279 * Adds the listener to the collection of listeners who will
280 * be notified when a drag and drop operation is in progress, by sending
281 * it one of the messages defined in the <code>DropTargetListener</code>
282 * interface.
283 *
284 * <p><ul>
285 * <li><code>dragEnter</code> is called when the cursor has entered the drop target boundaries
286 * <li><code>dragLeave</code> is called when the cursor has left the drop target boundaries and just before
287 * the drop occurs or is cancelled.
288 * <li><code>dragOperationChanged</code> is called when the operation being performed has changed
289 * (usually due to the user changing the selected modifier key(s) while dragging)
290 * <li><code>dragOver</code> is called when the cursor is moving over the drop target
291 * <li><code>dropAccept</code> is called just before the drop is performed. The drop target is given
292 * the chance to change the nature of the drop or veto the drop by setting the <code>event.detail</code> field
293 * <li><code>drop</code> is called when the data is being dropped
294 * </ul></p>
295 *
296 * @param listener the listener which should be notified
297 *
298 * @exception IllegalArgumentException <ul>
299 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
300 * </ul>
301 * @exception DWTException <ul>
302 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
303 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
304 * </ul>
305 *
306 * @see DropTargetListener
307 * @see #removeDropListener
308 * @see DropTargetEvent
309 */
310 public void addDropListener(DropTargetListener listener) {
311 if (listener is null) DND.error (DWT.ERROR_NULL_ARGUMENT);
312 DNDListener typedListener = new DNDListener (listener);
313 typedListener.dndWidget = this;
314 addListener (DND.DragEnter, typedListener);
315 addListener (DND.DragLeave, typedListener);
316 addListener (DND.DragOver, typedListener);
317 addListener (DND.DragOperationChanged, typedListener);
318 addListener (DND.Drop, typedListener);
319 addListener (DND.DropAccept, typedListener);
320 }
321
322 protected void checkSubclass () {
323 String name = getClass().getName ();
324 String validName = DropTarget.class.getName();
325 if (!validName.opEquals(name)) {
326 DND.error (DWT.ERROR_INVALID_SUBCLASS);
327 }
328 }
329
330 int dragReceiveHandler(int theWindow, int handlerRefCon, int theDrag) {
331 updateDragOverHover(0, null);
332 if (keyOperation is -1) return OS.dragNotAcceptedErr;
333
334 DNDEvent event = new DNDEvent();
335 event.widget = this;
336 event.time = (int)System.currentTimeMillis();
337 event.detail = DND.DROP_NONE;
338 notifyListeners(DND.DragLeave, event);
339
340 event = new DNDEvent();
341 if (!setEventData(theDrag, event)) {
342 return OS.dragNotAcceptedErr;
343 }
344
345 keyOperation = -1;
346 int allowedOperations = event.operations;
347 TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length];
348 System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, event.dataTypes.length);
349 event.dataType = selectedDataType;
350 event.detail = selectedOperation;
351 selectedDataType = null;
352 selectedOperation = DND.DROP_NONE;
353 notifyListeners(DND.DropAccept, event);
354
355 if (event.dataType !is null) {
356 for (int i = 0; i < allowedDataTypes.length; i++) {
357 if (allowedDataTypes[i].type is event.dataType.type) {
358 selectedDataType = allowedDataTypes[i];
359 break;
360 }
361 }
362 }
363 if (selectedDataType !is null && (event.detail & allowedOperations) !is 0) {
364 selectedOperation = event.detail;
365 }
366 if (selectedOperation is DND.DROP_NONE) {
367 // this was not a successful drop
368 return OS.dragNotAcceptedErr;
369 }
370 // ask drag source for dropped data
371 byte[][] data = new byte[0][];
372 // locate all the items with data of the desired type
373 short[] numItems = new short[1];
374 OS.CountDragItems(theDrag, numItems);
375 for (short i = 0; i < numItems[0]; i++) {
376 int[] theItemRef = new int[1];
377 OS.GetDragItemReferenceNumber(theDrag, (short) (i+1), theItemRef);
378 int[] size = new int[1];
379 OS.GetFlavorDataSize(theDrag, theItemRef[0], selectedDataType.type, size);
380 if (size[0] > 0) {
381 byte[] buffer = new byte[size[0]];
382 OS.GetFlavorData(theDrag, theItemRef[0], selectedDataType.type, buffer, size, 0);
383 byte[][] newData = new byte[data.length + 1][];
384 System.arraycopy(data, 0, newData, 0, data.length);
385 newData[data.length] = buffer;
386 data = newData;
387 }
388 }
389 // Get Data in a Java format
390 Object object = null;
391 for (int i = 0; i < transferAgents.length; i++) {
392 Transfer transfer = transferAgents[i];
393 if (transfer !is null && transfer.isSupportedType(selectedDataType)) {
394 selectedDataType.data = data;
395 object = transfer.nativeToJava(selectedDataType);
396 break;
397 }
398 }
399
400 if (object is null) {
401 selectedOperation = DND.DROP_NONE;
402 }
403
404 event.dataType = selectedDataType;
405 event.detail = selectedOperation;
406 event.data = object;
407 notifyListeners(DND.Drop, event);
408 selectedOperation = DND.DROP_NONE;
409 if ((allowedOperations & event.detail) is event.detail) {
410 selectedOperation = event.detail;
411 }
412 //notify source of action taken
413 int action = opToOsOp(selectedOperation);
414 OS.SetDragDropAction(theDrag, action);
415 return (selectedOperation is DND.DROP_NONE) ? OS.dragNotAcceptedErr : OS.noErr;
416 }
417
418 int dragTrackingHandler(int message, int theWindow, int handlerRefCon, int theDrag) {
419
420 if (message is OS.kDragTrackingLeaveWindow) {
421 updateDragOverHover(0, null);
422 OS.SetThemeCursor(OS.kThemeArrowCursor);
423 if (keyOperation is -1) return OS.dragNotAcceptedErr;
424 keyOperation = -1;
425
426 DNDEvent event = new DNDEvent();
427 event.widget = this;
428 event.time = (int)System.currentTimeMillis();
429 event.detail = DND.DROP_NONE;
430 notifyListeners(DND.DragLeave, event);
431 return OS.noErr;
432 }
433
434 int oldKeyOperation = keyOperation;
435
436 if (message is OS.kDragTrackingEnterWindow) {
437 selectedDataType = null;
438 selectedOperation = 0;
439 }
440
441 DNDEvent event = new DNDEvent();
442 if (!setEventData(theDrag, event)) {
443 keyOperation = -1;
444 OS.SetThemeCursor(OS.kThemeNotAllowedCursor);
445 return OS.dragNotAcceptedErr;
446 }
447
448 int allowedOperations = event.operations;
449 TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length];
450 System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length);
451
452 switch (message) {
453 case OS.kDragTrackingEnterWindow:
454 event.type = DND.DragEnter;
455 break;
456 case OS.kDragTrackingInWindow:
457 if (keyOperation is oldKeyOperation) {
458 event.type = DND.DragOver;
459 event.dataType = selectedDataType;
460 event.detail = selectedOperation;
461 }else {
462 event.type = DND.DragOperationChanged;
463 event.dataType = selectedDataType;
464 }
465 break;
466 }
467
468 updateDragOverHover(DRAGOVER_HYSTERESIS, event);
469 selectedDataType = null;
470 selectedOperation = DND.DROP_NONE;
471 notifyListeners(event.type, event);
472
473 if (event.detail is DND.DROP_DEFAULT) {
474 event.detail = (allowedOperations & DND.DROP_MOVE) !is 0 ? DND.DROP_MOVE : DND.DROP_NONE;
475 }
476
477 if (event.dataType !is null) {
478 for (int i = 0; i < allowedDataTypes.length; i++) {
479 if (allowedDataTypes[i].type is event.dataType.type) {
480 selectedDataType = allowedDataTypes[i];
481 break;
482 }
483 }
484 }
485
486 if (selectedDataType !is null && (allowedOperations & event.detail) !is 0) {
487 selectedOperation = event.detail;
488 }
489
490 OS.SetDragDropAction(theDrag, opToOsOp(selectedOperation));
491
492 switch (selectedOperation) {
493 case DND.DROP_COPY:
494 OS.SetThemeCursor(OS.kThemeCopyArrowCursor);
495 break;
496 case DND.DROP_LINK:
497 OS.SetThemeCursor(OS.kThemeAliasArrowCursor);
498 break;
499 case DND.DROP_MOVE:
500 OS.SetThemeCursor(OS.kThemeArrowCursor);
501 break;
502 default:
503 OS.SetThemeCursor(OS.kThemeNotAllowedCursor);
504 }
505
506 if (message is OS.kDragTrackingEnterWindow) {
507 dragOverHeartbeat.run();
508 }
509 return OS.noErr;
510 }
511
512 /**
513 * Returns the Control which is registered for this DropTarget. This is the control over which the
514 * user positions the cursor to drop the data.
515 *
516 * @return the Control which is registered for this DropTarget
517 */
518 public Control getControl () {
519 return control;
520 }
521
522 /**
523 * Returns an array of listeners who will be notified when a drag and drop
524 * operation is in progress, by sending it one of the messages defined in
525 * the <code>DropTargetListener</code> interface.
526 *
527 * @exception DWTException <ul>
528 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
529 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
530 * </ul>
531 *
532 * @see DropTargetListener
533 * @see #addDropListener
534 * @see #removeDropListener
535 * @see DropTargetEvent
536 *
537 * @since 3.4
538 */
539 public DropTargetListener[] getDropListeners() {
540 Listener[] listeners = getListeners(DND.DragEnter);
541 int length = listeners.length;
542 DropTargetListener[] dropListeners = new DropTargetListener[length];
543 int count = 0;
544 for (int i = 0; i < length; i++) {
545 Listener listener = listeners[i];
546 if (listener instanceof DNDListener) {
547 dropListeners[count] = (DropTargetListener) ((DNDListener) listener).getEventListener();
548 count++;
549 }
550 }
551 if (count is length) return dropListeners;
552 DropTargetListener[] result = new DropTargetListener[count];
553 System.arraycopy(dropListeners, 0, result, 0, count);
554 return result;
555 }
556
557 /**
558 * Returns the drop effect for this DropTarget. This drop effect will be
559 * used during a drag and drop to display the drag under effect on the
560 * target widget.
561 *
562 * @return the drop effect that is registered for this DropTarget
563 *
564 * @since 3.3
565 */
566 public DropTargetEffect getDropTargetEffect() {
567 return dropEffect;
568 }
569
570 int getOperationFromKeyState(int theDrag) {
571 short[] modifiers = new short[1];
572 OS.GetDragModifiers(theDrag, modifiers, null, null);
573 bool option = (modifiers[0] & OS.optionKey) is OS.optionKey;
574 bool command = (modifiers[0] & OS.cmdKey) is OS.cmdKey;
575 if (option && command) return DND.DROP_LINK;
576 if (option) return DND.DROP_COPY;
577 if (command) return DND.DROP_MOVE;
578 return DND.DROP_DEFAULT;
579 }
580
581 /**
582 * Returns a list of the data types that can be transferred to this DropTarget.
583 *
584 * @return a list of the data types that can be transferred to this DropTarget
585 */
586 public Transfer[] getTransfer() {
587 return transferAgents;
588 }
589
590 void onDispose () {
591 if (control is null)
592 return;
593 if (controlListener !is null)
594 control.removeListener(DWT.Dispose, controlListener);
595 controlListener = null;
596 control.setData(DND.DROP_TARGET_KEY, null);
597 transferAgents = null;
598 control = null;
599 }
600
601 int opToOsOp(int operation) {
602 int osOperation = 0;
603 if ((operation & DND.DROP_COPY) !is 0){
604 osOperation |= OS.kDragActionCopy;
605 }
606 if ((operation & DND.DROP_LINK) !is 0) {
607 osOperation |= OS.kDragActionAlias;
608 }
609 if ((operation & DND.DROP_MOVE) !is 0) {
610 osOperation |= OS.kDragActionMove;
611 }
612 return osOperation;
613 }
614
615 int osOpToOp(int osOperation){
616 int operation = 0;
617 if ((osOperation & OS.kDragActionCopy) !is 0){
618 operation |= DND.DROP_COPY;
619 }
620 if ((osOperation & OS.kDragActionAlias) !is 0) {
621 operation |= DND.DROP_LINK;
622 }
623 if ((osOperation & OS.kDragActionMove) !is 0) {
624 operation |= DND.DROP_MOVE;
625 }
626 if (osOperation is OS.kDragActionAll) {
627 operation = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK;
628 }
629 return operation;
630 }
631
632 /**
633 * Removes the listener from the collection of listeners who will
634 * be notified when a drag and drop operation is in progress.
635 *
636 * @param listener the listener which should be notified
637 *
638 * @exception IllegalArgumentException <ul>
639 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
640 * </ul>
641 * @exception DWTException <ul>
642 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
643 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
644 * </ul>
645 *
646 * @see DropTargetListener
647 * @see #addDropListener
648 */
649 public void removeDropListener(DropTargetListener listener) {
650 if (listener is null) DND.error (DWT.ERROR_NULL_ARGUMENT);
651 removeListener (DND.DragEnter, listener);
652 removeListener (DND.DragLeave, listener);
653 removeListener (DND.DragOver, listener);
654 removeListener (DND.DragOperationChanged, listener);
655 removeListener (DND.Drop, listener);
656 removeListener (DND.DropAccept, listener);
657 }
658
659 /**
660 * Specifies the drop effect for this DropTarget. This drop effect will be
661 * used during a drag and drop to display the drag under effect on the
662 * target widget.
663 *
664 * @param effect the drop effect that is registered for this DropTarget
665 *
666 * @since 3.3
667 */
668 public void setDropTargetEffect(DropTargetEffect effect) {
669 dropEffect = effect;
670 }
671
672 bool setEventData(int theDrag, DNDEvent event) {
673 if (theDrag is 0) return false;
674
675 // get allowed operations
676 int style = getStyle();
677 int[] outActions = new int[1];
678 OS.GetDragAllowableActions(theDrag, outActions);
679 int operations = osOpToOp(outActions[0]) & style;
680 if (operations is DND.DROP_NONE) return false;
681
682 //get current operation
683 int operation = getOperationFromKeyState(theDrag);
684 keyOperation = operation;
685 if (operation is DND.DROP_DEFAULT) {
686 if ((style & DND.DROP_DEFAULT) is 0) {
687 operation = (operations & DND.DROP_MOVE) !is 0 ? DND.DROP_MOVE : DND.DROP_NONE;
688 }
689 } else {
690 if ((operation & operations) is 0) operation = DND.DROP_NONE;
691 }
692
693 // get allowed transfer types
694 short[] numItems = new short[1];
695 OS.CountDragItems(theDrag, numItems);
696 int[] flavors = new int[10];
697 int index = -1;
698 //Get a unique list of flavors
699 for (short i = 0; i < numItems[0]; i++) {
700 int[] theItemRef = new int[1];
701 OS.GetDragItemReferenceNumber(theDrag, (short) (i+1), theItemRef);
702 short[] numFlavors = new short[1];
703 OS.CountDragItemFlavors(theDrag, theItemRef[0], numFlavors);
704 int[] theType = new int[1];
705 for (int j = 0; j < numFlavors[0]; j++) {
706 theType[0] = 0;
707 if (OS.GetFlavorType(theDrag, theItemRef[0], (short) (j+1), theType) is OS.noErr) {
708 bool unique = true;
709 for (int k = 0; k < flavors.length; k++) {
710 if (flavors[k] is theType[0]) {
711 unique = false;
712 break;
713 }
714 }
715 if (unique) {
716 if (index is flavors.length - 1) {
717 int[] temp = new int[flavors.length + 10];
718 System.arraycopy(flavors, 0, temp, 0, flavors.length);
719 flavors = temp;
720 }
721 flavors[++index] = theType[0];
722 }
723 }
724 }
725 }
726 if (index is -1) return false;
727
728 TransferData[] dataTypes = new TransferData[index+1];
729 index = -1;
730 for (int i = 0; i < dataTypes.length; i++) {
731 if (flavors[i] !is 0) {
732 TransferData data = new TransferData();
733 data.type = flavors[i];
734 for (int j = 0; j < transferAgents.length; j++) {
735 Transfer transfer = transferAgents[j];
736 if (transfer !is null && transfer.isSupportedType(data)) {
737 dataTypes[++index] = data;
738 break;
739 }
740 }
741 }
742 }
743 if (index is -1) return false;
744
745 if (index < dataTypes.length - 1) {
746 TransferData[] temp = new TransferData[index + 1];
747 System.arraycopy(dataTypes, 0, temp, 0, index + 1);
748 dataTypes = temp;
749 }
750
751 Point mouse = new Point();
752 OS.GetDragMouse(theDrag, mouse, null);
753
754 event.widget = this;
755 event.x = mouse.h;
756 event.y = mouse.v;
757 event.time = (int)System.currentTimeMillis();
758 event.feedback = DND.FEEDBACK_SELECT;
759 event.dataTypes = dataTypes;
760 event.dataType = dataTypes[0];
761 event.operations = operations;
762 event.detail = operation;
763 if (dropEffect !is null) {
764 event.item = dropEffect.getItem(event.x, event.y);
765 }
766
767 return true;
768 }
769
770 /**
771 * Specifies the data types that can be transferred to this DropTarget. If data is
772 * being dragged that does not match one of these types, the drop target will be notified of
773 * the drag and drop operation but the currentDataType will be null and the operation
774 * will be DND.NONE.
775 *
776 * @param transferAgents a list of Transfer objects which define the types of data that can be
777 * dropped on this target
778 *
779 * @exception IllegalArgumentException <ul>
780 * <li>ERROR_NULL_ARGUMENT - if transferAgents is null</li>
781 * </ul>
782 */
783 public void setTransfer(Transfer[] transferAgents){
784 if (transferAgents is null) DND.error(DWT.ERROR_NULL_ARGUMENT);
785 this.transferAgents = transferAgents;
786 }
787
788 void updateDragOverHover(long delay, DNDEvent event) {
789 if (delay is 0) {
790 dragOverStart = 0;
791 dragOverEvent = null;
792 return;
793 }
794 dragOverStart = System.currentTimeMillis() + delay;
795 if (dragOverEvent is null) dragOverEvent = new DNDEvent();
796 dragOverEvent.x = event.x;
797 dragOverEvent.y = event.y;
798 dragOverEvent.dataTypes = event.dataTypes;
799 dragOverEvent.operations = event.operations;
800 dragOverEvent.dataType = event.dataType;
801 dragOverEvent.detail = event.detail;
802 }
803
804 }