KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jface > viewers > ViewerDropAdapter


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 package org.eclipse.jface.viewers;
12
13 import org.eclipse.swt.dnd.DND;
14 import org.eclipse.swt.dnd.DropTargetAdapter;
15 import org.eclipse.swt.dnd.DropTargetEvent;
16 import org.eclipse.swt.dnd.TransferData;
17 import org.eclipse.swt.graphics.Point;
18 import org.eclipse.swt.graphics.Rectangle;
19 import org.eclipse.swt.widgets.Item;
20 import org.eclipse.swt.widgets.TableItem;
21 import org.eclipse.swt.widgets.TreeItem;
22
23 /**
24  * This adapter class provides generic drag-and-drop support for a viewer.
25  * <p>
26  * Subclasses must implement the following methods:
27  * <ul>
28  * <li><code>validateDrop</code> - identifies valid drop targets in viewer</li>
29  * <li><code>performDrop</code> - carries out a drop into a viewer</li>
30  * </ul>
31  * The <code>setFeedbackEnabled</code> method can be called to turn on and off
32  * visual insertion feedback (on by default).
33  * </p>
34  */

35 public abstract class ViewerDropAdapter extends DropTargetAdapter {
36
37     /**
38      * Constant describing the position of the cursor relative
39      * to the target object. This means the mouse is positioned
40      * slightly before the target.
41      * @see #getCurrentLocation()
42      */

43     public static final int LOCATION_BEFORE = 1;
44
45     /**
46      * Constant describing the position of the cursor relative
47      * to the target object. This means the mouse is positioned
48      * slightly after the target.
49      * @see #getCurrentLocation()
50      */

51     public static final int LOCATION_AFTER = 2;
52
53     /**
54      * Constant describing the position of the cursor relative
55      * to the target object. This means the mouse is positioned
56      * directly on the target.
57      * @see #getCurrentLocation()
58      */

59     public static final int LOCATION_ON = 3;
60
61     /**
62      * Constant describing the position of the cursor relative
63      * to the target object. This means the mouse is not positioned
64      * over or near any valid target.
65      * @see #getCurrentLocation()
66      */

67     public static final int LOCATION_NONE = 4;
68
69     /**
70      * The viewer to which this drop support has been added.
71      */

72     private Viewer viewer;
73
74     /**
75      * The current operation.
76      */

77     private int currentOperation = DND.DROP_NONE;
78
79     /**
80      * The last valid operation.
81      */

82     private int lastValidOperation = DND.DROP_NONE;
83
84     /**
85      * The data item currently under the mouse.
86      */

87     private Object JavaDoc currentTarget;
88
89     /**
90      * Information about the position of the mouse relative to the
91      * target (before, on, or after the target. Location is one of
92      * the <code>LOCATION_* </code> constants defined in this type.
93      */

94     private int currentLocation;
95
96     /**
97      * A flag that allows adapter users to turn the insertion
98      * feedback on or off. Default is <code>true</code>.
99      */

100     private boolean feedbackEnabled = true;
101
102     /**
103      * A flag that allows adapter users to turn auto scrolling
104      * and expanding on or off. Default is <code>true</code>.
105      */

106     private boolean scrollExpandEnabled = true;
107
108     /**
109      * A flag that allows adapter users to turn selection feedback
110      * on or off. Default is <code>true</code>.
111      */

112     private boolean selectFeedbackEnabled = true;
113
114     /**
115      * Creates a new drop adapter for the given viewer.
116      *
117      * @param viewer the viewer
118      */

119     protected ViewerDropAdapter(Viewer viewer) {
120         this.viewer = viewer;
121     }
122
123     /**
124      * Returns the position of the given event's coordinates relative to its target.
125      * The position is determined to be before, after, or on the item, based on
126      * some threshold value.
127      *
128      * @param event the event
129      * @return one of the <code>LOCATION_* </code>constants defined in this class
130      */

131     protected int determineLocation(DropTargetEvent event) {
132         if (!(event.item instanceof Item)) {
133             return LOCATION_NONE;
134         }
135         Item item = (Item) event.item;
136         Point coordinates = new Point(event.x, event.y);
137         coordinates = viewer.getControl().toControl(coordinates);
138         if (item != null) {
139             Rectangle bounds = getBounds(item);
140             if (bounds == null) {
141                 return LOCATION_NONE;
142             }
143             if ((coordinates.y - bounds.y) < 5) {
144                 return LOCATION_BEFORE;
145             }
146             if ((bounds.y + bounds.height - coordinates.y) < 5) {
147                 return LOCATION_AFTER;
148             }
149         }
150         return LOCATION_ON;
151     }
152
153     /**
154      * Returns the target item of the given drop event.
155      *
156      * @param event the event
157      * @return The target of the drop, may be <code>null</code>.
158      */

159     protected Object JavaDoc determineTarget(DropTargetEvent event) {
160         return event.item == null ? null : event.item.getData();
161     }
162
163     /* (non-Javadoc)
164      * Method declared on DropTargetAdapter.
165      * The mouse has moved over the drop target. If the
166      * target item has changed, notify the action and check
167      * that it is still enabled.
168      */

169     private void doDropValidation(DropTargetEvent event) {
170         //update last valid operation
171
if (event.detail != DND.DROP_NONE) {
172             lastValidOperation = event.detail;
173         }
174         //valid drop and set event detail accordingly
175
if (validateDrop(currentTarget, event.detail, event.currentDataType)) {
176             currentOperation = lastValidOperation;
177         } else {
178             currentOperation = DND.DROP_NONE;
179         }
180         event.detail = currentOperation;
181     }
182
183     /* (non-Javadoc)
184      * Method declared on DropTargetAdapter.
185      * The drag has entered this widget's region. See
186      * if the drop should be allowed.
187      */

188     public void dragEnter(DropTargetEvent event) {
189         currentTarget = determineTarget(event);
190         doDropValidation(event);
191     }
192
193     /* (non-Javadoc)
194      * Method declared on DropTargetAdapter.
195      * The drop operation has changed, see if the action
196      * should still be enabled.
197      */

198     public void dragOperationChanged(DropTargetEvent event) {
199         currentTarget = determineTarget(event);
200         doDropValidation(event);
201     }
202
203     /* (non-Javadoc)
204      * Method declared on DropTargetAdapter.
205      * The mouse has moved over the drop target. If the
206      * target item has changed, notify the action and check
207      * that it is still enabled.
208      */

209     public void dragOver(DropTargetEvent event) {
210         //use newly revealed item as target if scrolling occurs
211
Object JavaDoc target = determineTarget(event);
212
213         //set the location feedback
214
int oldLocation = currentLocation;
215         currentLocation = determineLocation(event);
216         setFeedback(event, currentLocation);
217
218         //see if anything has really changed before doing validation.
219
if (target != currentTarget || currentLocation != oldLocation) {
220             currentTarget = target;
221             doDropValidation(event);
222         }
223     }
224
225     /* (non-Javadoc)
226      * Method declared on DropTargetAdapter.
227      * The user has dropped something on the desktop viewer.
228      */

229     public void drop(DropTargetEvent event) {
230         currentLocation = determineLocation(event);
231
232         //perform the drop behavior
233
if (!performDrop(event.data)) {
234             event.detail = DND.DROP_NONE;
235         }
236         currentOperation = event.detail;
237     }
238
239     /* (non-Javadoc)
240      * Method declared on DropTargetAdapter.
241      * Last chance for the action to disable itself
242      */

243     public void dropAccept(DropTargetEvent event) {
244         if (!validateDrop(currentTarget, event.detail, event.currentDataType)) {
245             event.detail = DND.DROP_NONE;
246         }
247     }
248
249     /**
250      * Returns the bounds of the given SWT tree or table item.
251      *
252      * @param item the SWT Item
253      * @return the bounds, or <code>null</code> if it is not a known type of item
254      */

255     protected Rectangle getBounds(Item item) {
256         if (item instanceof TreeItem) {
257             return ((TreeItem) item).getBounds();
258         }
259         if (item instanceof TableItem) {
260             return ((TableItem) item).getBounds(0);
261         }
262         return null;
263     }
264
265     /**
266      * Returns a constant describing the position of the mouse relative to the
267      * target (before, on, or after the target.
268      *
269      * @return one of the <code>LOCATION_* </code> constants defined in this type
270      */

271     protected int getCurrentLocation() {
272         return currentLocation;
273     }
274
275     /**
276      * Returns the current operation.
277      *
278      * @return a <code>DROP_*</code> constant from class <code>DND</code>
279      *
280      * @see DND#DROP_COPY
281      * @see DND#DROP_MOVE
282      * @see DND#DROP_LINK
283      * @see DND#DROP_NONE
284      */

285     protected int getCurrentOperation() {
286         return currentOperation;
287     }
288
289     /**
290      * Returns the target object currently under the mouse.
291      *
292      * @return the current target object
293      */

294     protected Object JavaDoc getCurrentTarget() {
295         return currentTarget;
296     }
297
298     /**
299      * Returns whether visible insertion feedback should be presented to the user.
300      * <p>
301      * Typical insertion feedback is the horizontal insertion bars that appear
302      * between adjacent items while dragging.
303      * </p>
304      *
305      * @return <code>true</code> if visual feedback is desired, and <code>false</code> if not
306      */

307     public boolean getFeedbackEnabled() {
308         return feedbackEnabled;
309     }
310
311     /**
312      * Returns the object currently selected by the viewer.
313      *
314      * @return the selected object, or <code>null</code> if either no object or
315      * multiple objects are selected
316      */

317     protected Object JavaDoc getSelectedObject() {
318         ISelection selection = viewer.getSelection();
319         if (selection instanceof IStructuredSelection && !selection.isEmpty()) {
320             IStructuredSelection structured = (IStructuredSelection) selection;
321             return structured.getFirstElement();
322         }
323         return null;
324     }
325
326     /**
327      * @return the viewer to which this drop support has been added.
328      */

329     protected Viewer getViewer() {
330         return viewer;
331     }
332
333     /**
334      * @deprecated this method should not be used. Exception handling has been
335      * removed from DropTargetAdapter methods overridden by this class.
336      * Handles any exception that occurs during callback, including
337      * rethrowing behavior.
338      * <p>
339      * [Issue: Implementation prints stack trace and eats exception to avoid
340      * crashing VA/J.
341      * Consider conditionalizing the implementation to do one thing in VAJ
342      * and something more reasonable in other operating environments.
343      * ]
344      * </p>
345      *
346      * @param exception the exception
347      * @param event the event
348      */

349     protected void handleException(Throwable JavaDoc exception, DropTargetEvent event) {
350         // Currently we never rethrow because VA/Java crashes if an SWT
351
// callback throws anything. Generally catching Throwable is bad, but in
352
// this cases it's better than hanging the image.
353
exception.printStackTrace();
354         event.detail = DND.DROP_NONE;
355     }
356
357     /**
358      * Performs any work associated with the drop.
359      * <p>
360      * Subclasses must implement this method to provide drop behavior.
361      * </p>
362      *
363      * @param data the drop data
364      * @return <code>true</code> if the drop was successful, and
365      * <code>false</code> otherwise
366      */

367     public abstract boolean performDrop(Object JavaDoc data);
368
369     /* (non-Javadoc)
370      * Method declared on DropTargetAdapter.
371      * The mouse has moved over the drop target. If the
372      * target item has changed, notify the action and check
373      * that it is still enabled.
374      */

375     private void setFeedback(DropTargetEvent event, int location) {
376         if (feedbackEnabled) {
377             switch (location) {
378             case LOCATION_BEFORE:
379                 event.feedback = DND.FEEDBACK_INSERT_BEFORE;
380                 break;
381             case LOCATION_AFTER:
382                 event.feedback = DND.FEEDBACK_INSERT_AFTER;
383                 break;
384             case LOCATION_ON:
385             default:
386                 event.feedback = DND.FEEDBACK_SELECT;
387                 break;
388             }
389         }
390         
391          // Explicitly inhibit SELECT feedback if desired
392
if (!selectFeedbackEnabled) {
393             event.feedback &= ~DND.FEEDBACK_SELECT;
394         }
395
396         if (scrollExpandEnabled) {
397             event.feedback |= DND.FEEDBACK_EXPAND | DND.FEEDBACK_SCROLL;
398         }
399     }
400
401     /**
402      * Sets whether visible insertion feedback should be presented to the user.
403      * <p>
404      * Typical insertion feedback is the horizontal insertion bars that appear
405      * between adjacent items while dragging.
406      * </p>
407      *
408      * @param value
409      * <code>true</code> if visual feedback is desired, and
410      * <code>false</code> if not
411      */

412     public void setFeedbackEnabled(boolean value) {
413         feedbackEnabled = value;
414     }
415
416     /**
417      * Sets whether selection feedback should be provided during dragging.
418      *
419      * @param value <code>true</code> if selection feedback is desired, and
420      * <code>false</code> if not
421      *
422      * @since 3.2
423      */

424     public void setSelectionFeedbackEnabled(boolean value) {
425         selectFeedbackEnabled = value;
426     }
427
428     /**
429      * Sets whether auto scrolling and expanding should be provided during dragging.
430      *
431      * @param value <code>true</code> if scrolling and expanding is desired, and
432      * <code>false</code> if not
433      * @since 2.0
434      */

435     public void setScrollExpandEnabled(boolean value) {
436         scrollExpandEnabled = value;
437     }
438
439     /**
440      * Validates dropping on the given object. This method is called whenever some
441      * aspect of the drop operation changes.
442      * <p>
443      * Subclasses must implement this method to define which drops make sense.
444      * </p>
445      *
446      * @param target the object that the mouse is currently hovering over, or
447      * <code>null</code> if the mouse is hovering over empty space
448      * @param operation the current drag operation (copy, move, etc.)
449      * @param transferType the current transfer type
450      * @return <code>true</code> if the drop is valid, and <code>false</code>
451      * otherwise
452      */

453     public abstract boolean validateDrop(Object JavaDoc target, int operation,
454             TransferData transferType);
455 }
456
Popular Tags