10
|
1 /*******************************************************************************
|
|
2 * Copyright (c) 2000, 2007 IBM Corporation and others.
|
|
3 * All rights reserved. This program and the accompanying materials
|
|
4 * are made available under the terms of the Eclipse Public License v1.0
|
|
5 * which accompanies this distribution, and is available at
|
|
6 * http://www.eclipse.org/legal/epl-v10.html
|
|
7 *
|
|
8 * Contributors:
|
|
9 * IBM Corporation - initial API and implementation
|
|
10 * Port to the D programming language:
|
|
11 * Frank Benoit <benoit@tionex.de>
|
|
12 *******************************************************************************/
|
|
13 module dwtx.jface.viewers.ViewerDropAdapter;
|
|
14
|
|
15 import dwtx.jface.viewers.Viewer;
|
|
16 import dwtx.jface.viewers.IStructuredSelection;
|
|
17 import dwtx.jface.viewers.ISelection;
|
|
18
|
|
19 import dwt.dnd.DND;
|
|
20 import dwt.dnd.DropTargetAdapter;
|
|
21 import dwt.dnd.DropTargetEvent;
|
|
22 import dwt.dnd.TransferData;
|
|
23 import dwt.graphics.Point;
|
|
24 import dwt.graphics.Rectangle;
|
|
25 import dwt.widgets.Item;
|
|
26 import dwt.widgets.TableItem;
|
|
27 import dwt.widgets.TreeItem;
|
|
28
|
|
29 import dwt.dwthelper.utils;
|
|
30
|
|
31 /**
|
|
32 * This adapter class provides generic drag-and-drop support for a viewer.
|
|
33 * <p>
|
|
34 * Subclasses must implement the following methods:
|
|
35 * <ul>
|
|
36 * <li><code>validateDrop</code> - identifies valid drop targets in viewer</li>
|
|
37 * <li><code>performDrop</code> - carries out a drop into a viewer</li>
|
|
38 * </ul>
|
|
39 * The <code>setFeedbackEnabled</code> method can be called to turn on and off
|
|
40 * visual insertion feedback (on by default).
|
|
41 * </p>
|
|
42 */
|
|
43 public abstract class ViewerDropAdapter : DropTargetAdapter {
|
|
44
|
|
45 /**
|
|
46 * Constant describing the position of the cursor relative
|
|
47 * to the target object. This means the mouse is positioned
|
|
48 * slightly before the target.
|
|
49 * @see #getCurrentLocation()
|
|
50 */
|
|
51 public static const int LOCATION_BEFORE = 1;
|
|
52
|
|
53 /**
|
|
54 * Constant describing the position of the cursor relative
|
|
55 * to the target object. This means the mouse is positioned
|
|
56 * slightly after the target.
|
|
57 * @see #getCurrentLocation()
|
|
58 */
|
|
59 public static const int LOCATION_AFTER = 2;
|
|
60
|
|
61 /**
|
|
62 * Constant describing the position of the cursor relative
|
|
63 * to the target object. This means the mouse is positioned
|
|
64 * directly on the target.
|
|
65 * @see #getCurrentLocation()
|
|
66 */
|
|
67 public static const int LOCATION_ON = 3;
|
|
68
|
|
69 /**
|
|
70 * Constant describing the position of the cursor relative
|
|
71 * to the target object. This means the mouse is not positioned
|
|
72 * over or near any valid target.
|
|
73 * @see #getCurrentLocation()
|
|
74 */
|
|
75 public static const int LOCATION_NONE = 4;
|
|
76
|
|
77 /**
|
|
78 * The viewer to which this drop support has been added.
|
|
79 */
|
|
80 private Viewer viewer;
|
|
81
|
|
82 /**
|
|
83 * The current operation.
|
|
84 */
|
|
85 private int currentOperation = DND.DROP_NONE;
|
|
86
|
|
87 /**
|
|
88 * The last valid operation.
|
|
89 */
|
|
90 private int lastValidOperation = DND.DROP_NONE;
|
|
91
|
|
92 /**
|
|
93 * The data item currently under the mouse.
|
|
94 */
|
|
95 private Object currentTarget;
|
|
96
|
|
97 /**
|
|
98 * Information about the position of the mouse relative to the
|
|
99 * target (before, on, or after the target. Location is one of
|
|
100 * the <code>LOCATION_* </code> constants defined in this type.
|
|
101 */
|
|
102 private int currentLocation;
|
|
103
|
|
104 /**
|
|
105 * A flag that allows adapter users to turn the insertion
|
|
106 * feedback on or off. Default is <code>true</code>.
|
|
107 */
|
|
108 private bool feedbackEnabled = true;
|
|
109
|
|
110 /**
|
|
111 * A flag that allows adapter users to turn auto scrolling
|
|
112 * and expanding on or off. Default is <code>true</code>.
|
|
113 */
|
|
114 private bool scrollExpandEnabled = true;
|
|
115
|
|
116 /**
|
|
117 * A flag that allows adapter users to turn selection feedback
|
|
118 * on or off. Default is <code>true</code>.
|
|
119 */
|
|
120 private bool selectFeedbackEnabled = true;
|
|
121
|
|
122 /**
|
|
123 * Creates a new drop adapter for the given viewer.
|
|
124 *
|
|
125 * @param viewer the viewer
|
|
126 */
|
|
127 protected this(Viewer viewer) {
|
|
128 this.viewer = viewer;
|
|
129 }
|
|
130
|
|
131 /**
|
|
132 * Returns the position of the given event's coordinates relative to its target.
|
|
133 * The position is determined to be before, after, or on the item, based on
|
|
134 * some threshold value.
|
|
135 *
|
|
136 * @param event the event
|
|
137 * @return one of the <code>LOCATION_* </code>constants defined in this class
|
|
138 */
|
|
139 protected int determineLocation(DropTargetEvent event) {
|
|
140 if (!( cast(Item)event.item )) {
|
|
141 return LOCATION_NONE;
|
|
142 }
|
|
143 Item item = cast(Item) event.item;
|
|
144 Point coordinates = new Point(event.x, event.y);
|
|
145 coordinates = viewer.getControl().toControl(coordinates);
|
|
146 if (item !is null) {
|
|
147 Rectangle bounds = getBounds(item);
|
|
148 if (bounds is null) {
|
|
149 return LOCATION_NONE;
|
|
150 }
|
|
151 if ((coordinates.y - bounds.y) < 5) {
|
|
152 return LOCATION_BEFORE;
|
|
153 }
|
|
154 if ((bounds.y + bounds.height - coordinates.y) < 5) {
|
|
155 return LOCATION_AFTER;
|
|
156 }
|
|
157 }
|
|
158 return LOCATION_ON;
|
|
159 }
|
|
160
|
|
161 /**
|
|
162 * Returns the target item of the given drop event.
|
|
163 *
|
|
164 * @param event the event
|
|
165 * @return The target of the drop, may be <code>null</code>.
|
|
166 */
|
|
167 protected Object determineTarget(DropTargetEvent event) {
|
|
168 return event.item is null ? null : event.item.getData();
|
|
169 }
|
|
170
|
|
171 /* (non-Javadoc)
|
|
172 * Method declared on DropTargetAdapter.
|
|
173 * The mouse has moved over the drop target. If the
|
|
174 * target item has changed, notify the action and check
|
|
175 * that it is still enabled.
|
|
176 */
|
|
177 private void doDropValidation(DropTargetEvent event) {
|
|
178 //update last valid operation
|
|
179 if (event.detail !is DND.DROP_NONE) {
|
|
180 lastValidOperation = event.detail;
|
|
181 }
|
|
182 //valid drop and set event detail accordingly
|
|
183 if (validateDrop(currentTarget, event.detail, event.currentDataType)) {
|
|
184 currentOperation = lastValidOperation;
|
|
185 } else {
|
|
186 currentOperation = DND.DROP_NONE;
|
|
187 }
|
|
188 event.detail = currentOperation;
|
|
189 }
|
|
190
|
|
191 /* (non-Javadoc)
|
|
192 * Method declared on DropTargetAdapter.
|
|
193 * The drag has entered this widget's region. See
|
|
194 * if the drop should be allowed.
|
|
195 */
|
|
196 public void dragEnter(DropTargetEvent event) {
|
|
197 currentTarget = determineTarget(event);
|
|
198 doDropValidation(event);
|
|
199 }
|
|
200
|
|
201 /* (non-Javadoc)
|
|
202 * Method declared on DropTargetAdapter.
|
|
203 * The drop operation has changed, see if the action
|
|
204 * should still be enabled.
|
|
205 */
|
|
206 public void dragOperationChanged(DropTargetEvent event) {
|
|
207 currentTarget = determineTarget(event);
|
|
208 doDropValidation(event);
|
|
209 }
|
|
210
|
|
211 /* (non-Javadoc)
|
|
212 * Method declared on DropTargetAdapter.
|
|
213 * The mouse has moved over the drop target. If the
|
|
214 * target item has changed, notify the action and check
|
|
215 * that it is still enabled.
|
|
216 */
|
|
217 public void dragOver(DropTargetEvent event) {
|
|
218 //use newly revealed item as target if scrolling occurs
|
|
219 Object target = determineTarget(event);
|
|
220
|
|
221 //set the location feedback
|
|
222 int oldLocation = currentLocation;
|
|
223 currentLocation = determineLocation(event);
|
|
224 setFeedback(event, currentLocation);
|
|
225
|
|
226 //see if anything has really changed before doing validation.
|
|
227 if (target !is currentTarget || currentLocation !is oldLocation) {
|
|
228 currentTarget = target;
|
|
229 doDropValidation(event);
|
|
230 }
|
|
231 }
|
|
232
|
|
233 /* (non-Javadoc)
|
|
234 * Method declared on DropTargetAdapter.
|
|
235 * The user has dropped something on the desktop viewer.
|
|
236 */
|
|
237 public void drop(DropTargetEvent event) {
|
|
238 currentLocation = determineLocation(event);
|
|
239
|
|
240 //perform the drop behavior
|
|
241 if (!performDrop(event.data)) {
|
|
242 event.detail = DND.DROP_NONE;
|
|
243 }
|
|
244 currentOperation = event.detail;
|
|
245 }
|
|
246
|
|
247 /* (non-Javadoc)
|
|
248 * Method declared on DropTargetAdapter.
|
|
249 * Last chance for the action to disable itself
|
|
250 */
|
|
251 public void dropAccept(DropTargetEvent event) {
|
|
252 if (!validateDrop(currentTarget, event.detail, event.currentDataType)) {
|
|
253 event.detail = DND.DROP_NONE;
|
|
254 }
|
|
255 }
|
|
256
|
|
257 /**
|
|
258 * Returns the bounds of the given DWT tree or table item.
|
|
259 *
|
|
260 * @param item the DWT Item
|
|
261 * @return the bounds, or <code>null</code> if it is not a known type of item
|
|
262 */
|
|
263 protected Rectangle getBounds(Item item) {
|
|
264 if ( auto i = cast(TreeItem)item ) {
|
|
265 return i.getBounds();
|
|
266 }
|
|
267 if (auto i = cast(TableItem)item ) {
|
|
268 return i.getBounds(0);
|
|
269 }
|
|
270 return null;
|
|
271 }
|
|
272
|
|
273 /**
|
|
274 * Returns a constant describing the position of the mouse relative to the
|
|
275 * target (before, on, or after the target.
|
|
276 *
|
|
277 * @return one of the <code>LOCATION_* </code> constants defined in this type
|
|
278 */
|
|
279 protected int getCurrentLocation() {
|
|
280 return currentLocation;
|
|
281 }
|
|
282
|
|
283 /**
|
|
284 * Returns the current operation.
|
|
285 *
|
|
286 * @return a <code>DROP_*</code> constant from class <code>DND</code>
|
|
287 *
|
|
288 * @see DND#DROP_COPY
|
|
289 * @see DND#DROP_MOVE
|
|
290 * @see DND#DROP_LINK
|
|
291 * @see DND#DROP_NONE
|
|
292 */
|
|
293 protected int getCurrentOperation() {
|
|
294 return currentOperation;
|
|
295 }
|
|
296
|
|
297 /**
|
|
298 * Returns the target object currently under the mouse.
|
|
299 *
|
|
300 * @return the current target object
|
|
301 */
|
|
302 protected Object getCurrentTarget() {
|
|
303 return currentTarget;
|
|
304 }
|
|
305
|
|
306 /**
|
|
307 * Returns whether visible insertion feedback should be presented to the user.
|
|
308 * <p>
|
|
309 * Typical insertion feedback is the horizontal insertion bars that appear
|
|
310 * between adjacent items while dragging.
|
|
311 * </p>
|
|
312 *
|
|
313 * @return <code>true</code> if visual feedback is desired, and <code>false</code> if not
|
|
314 */
|
|
315 public bool getFeedbackEnabled() {
|
|
316 return feedbackEnabled;
|
|
317 }
|
|
318
|
|
319 /**
|
|
320 * Returns the object currently selected by the viewer.
|
|
321 *
|
|
322 * @return the selected object, or <code>null</code> if either no object or
|
|
323 * multiple objects are selected
|
|
324 */
|
|
325 protected Object getSelectedObject() {
|
|
326 ISelection selection = viewer.getSelection();
|
|
327 if ( null !is cast(IStructuredSelection) selection && !selection.isEmpty()) {
|
|
328 IStructuredSelection structured = cast(IStructuredSelection) selection;
|
|
329 return structured.getFirstElement();
|
|
330 }
|
|
331 return null;
|
|
332 }
|
|
333
|
|
334 /**
|
|
335 * @return the viewer to which this drop support has been added.
|
|
336 */
|
|
337 protected Viewer getViewer() {
|
|
338 return viewer;
|
|
339 }
|
|
340
|
|
341 /**
|
|
342 * @deprecated this method should not be used. Exception handling has been
|
|
343 * removed from DropTargetAdapter methods overridden by this class.
|
|
344 * Handles any exception that occurs during callback, including
|
|
345 * rethrowing behavior.
|
|
346 * <p>
|
|
347 * [Issue: Implementation prints stack trace and eats exception to avoid
|
|
348 * crashing VA/J.
|
|
349 * Consider conditionalizing the implementation to do one thing in VAJ
|
|
350 * and something more reasonable in other operating environments.
|
|
351 * ]
|
|
352 * </p>
|
|
353 *
|
|
354 * @param exception the exception
|
|
355 * @param event the event
|
|
356 */
|
|
357 protected void handleException(Exception exception, DropTargetEvent event) {
|
|
358 // Currently we never rethrow because VA/Java crashes if an DWT
|
|
359 // callback throws anything. Generally catching Throwable is bad, but in
|
|
360 // this cases it's better than hanging the image.
|
|
361 ExceptionPrintStackTrace( exception );
|
|
362 event.detail = DND.DROP_NONE;
|
|
363 }
|
|
364
|
|
365 /**
|
|
366 * Performs any work associated with the drop.
|
|
367 * <p>
|
|
368 * Subclasses must implement this method to provide drop behavior.
|
|
369 * </p>
|
|
370 *
|
|
371 * @param data the drop data
|
|
372 * @return <code>true</code> if the drop was successful, and
|
|
373 * <code>false</code> otherwise
|
|
374 */
|
|
375 public abstract bool performDrop(Object data);
|
|
376
|
|
377 /* (non-Javadoc)
|
|
378 * Method declared on DropTargetAdapter.
|
|
379 * The mouse has moved over the drop target. If the
|
|
380 * target item has changed, notify the action and check
|
|
381 * that it is still enabled.
|
|
382 */
|
|
383 private void setFeedback(DropTargetEvent event, int location) {
|
|
384 if (feedbackEnabled) {
|
|
385 switch (location) {
|
|
386 case LOCATION_BEFORE:
|
|
387 event.feedback = DND.FEEDBACK_INSERT_BEFORE;
|
|
388 break;
|
|
389 case LOCATION_AFTER:
|
|
390 event.feedback = DND.FEEDBACK_INSERT_AFTER;
|
|
391 break;
|
|
392 case LOCATION_ON:
|
|
393 default:
|
|
394 event.feedback = DND.FEEDBACK_SELECT;
|
|
395 break;
|
|
396 }
|
|
397 }
|
|
398
|
|
399 // Explicitly inhibit SELECT feedback if desired
|
|
400 if (!selectFeedbackEnabled) {
|
|
401 event.feedback &= ~DND.FEEDBACK_SELECT;
|
|
402 }
|
|
403
|
|
404 if (scrollExpandEnabled) {
|
|
405 event.feedback |= DND.FEEDBACK_EXPAND | DND.FEEDBACK_SCROLL;
|
|
406 }
|
|
407 }
|
|
408
|
|
409 /**
|
|
410 * Sets whether visible insertion feedback should be presented to the user.
|
|
411 * <p>
|
|
412 * Typical insertion feedback is the horizontal insertion bars that appear
|
|
413 * between adjacent items while dragging.
|
|
414 * </p>
|
|
415 *
|
|
416 * @param value
|
|
417 * <code>true</code> if visual feedback is desired, and
|
|
418 * <code>false</code> if not
|
|
419 */
|
|
420 public void setFeedbackEnabled(bool value) {
|
|
421 feedbackEnabled = value;
|
|
422 }
|
|
423
|
|
424 /**
|
|
425 * Sets whether selection feedback should be provided during dragging.
|
|
426 *
|
|
427 * @param value <code>true</code> if selection feedback is desired, and
|
|
428 * <code>false</code> if not
|
|
429 *
|
|
430 * @since 3.2
|
|
431 */
|
|
432 public void setSelectionFeedbackEnabled(bool value) {
|
|
433 selectFeedbackEnabled = value;
|
|
434 }
|
|
435
|
|
436 /**
|
|
437 * Sets whether auto scrolling and expanding should be provided during dragging.
|
|
438 *
|
|
439 * @param value <code>true</code> if scrolling and expanding is desired, and
|
|
440 * <code>false</code> if not
|
|
441 * @since 2.0
|
|
442 */
|
|
443 public void setScrollExpandEnabled(bool value) {
|
|
444 scrollExpandEnabled = value;
|
|
445 }
|
|
446
|
|
447 /**
|
|
448 * Validates dropping on the given object. This method is called whenever some
|
|
449 * aspect of the drop operation changes.
|
|
450 * <p>
|
|
451 * Subclasses must implement this method to define which drops make sense.
|
|
452 * </p>
|
|
453 *
|
|
454 * @param target the object that the mouse is currently hovering over, or
|
|
455 * <code>null</code> if the mouse is hovering over empty space
|
|
456 * @param operation the current drag operation (copy, move, etc.)
|
|
457 * @param transferType the current transfer type
|
|
458 * @return <code>true</code> if the drop is valid, and <code>false</code>
|
|
459 * otherwise
|
|
460 */
|
|
461 public abstract bool validateDrop(Object target, int operation,
|
|
462 TransferData transferType);
|
|
463 }
|