1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.ui.dnd;
13 import org.eclipse.swt.dnd.DND;
14 import org.eclipse.swt.dnd.DropTargetEvent;
15 import org.eclipse.swt.dnd.DropTargetListener;
16 import org.eclipse.swt.graphics.Point;
17 import org.eclipse.swt.graphics.Rectangle;
18 import org.eclipse.swt.widgets.Item;
19 import org.eclipse.swt.widgets.TableItem;
20 import org.eclipse.swt.widgets.TreeItem;
22 import org.eclipse.jface.util.Assert;
23 import org.eclipse.jface.viewers.StructuredViewer;
26 * A drag and drop adapter to be used together with structured viewers.
27 * The adapater delegates the <code>dragEnter</code>, <code>dragOperationChanged
28 * </code>, <code>dragOver</code> and <code>dropAccept</code> method to the
29 * <code>validateDrop</code> method. Furthermore it adds location feedback.
31 public class JdtViewerDropAdapter implements DropTargetListener {
34 * Constant describing the position of the mouse cursor relative
35 * to the target object. This means the mouse is positioned
36 * slightly before the target.
38 protected static final int LOCATION_BEFORE= 1;
41 * Constant describing the position of the mouse cursor relative
42 * to the target object. This means the mouse is positioned
43 * slightly after the target.
45 protected static final int LOCATION_AFTER= 2;
48 * Constant describing the position of the mouse cursor relative
49 * to the target object. This means the mouse is positioned
50 * directly on the target.
52 protected static final int LOCATION_ON= 3;
55 * Constant describing the position of the mouse cursor relative
56 * to the target object. This means the mouse is not positioned
57 * over or near any valid target.
59 protected static final int LOCATION_NONE= 4;
62 * The threshold used to determine if the mouse is before or after
65 private static final int LOCATION_EPSILON= 5;
68 * Style to enable location feedback.
70 public static final int INSERTION_FEEDBACK= 1 << 1;
72 private StructuredViewer fViewer;
73 private int fFeedback;
74 private boolean fShowInsertionFeedback;
75 private int fRequestedOperation;
76 private int fLastOperation;
77 protected int fLocation;
78 protected Object fTarget;
80 public JdtViewerDropAdapter(StructuredViewer viewer, int feedback) {
82 Assert.isNotNull(fViewer);
88 * Controls whether the drop adapter shows insertion feedback or not.
90 * @param showInsertionFeedback <code>true</code> if the drop adapter is supposed
91 * to show insertion feedback. Otherwise <code>false</code>
93 public void showInsertionFeedback(boolean showInsertionFeedback) {
94 fShowInsertionFeedback= showInsertionFeedback;
98 * Returns the viewer this adapter is working on.
100 protected StructuredViewer getViewer() {
104 //---- Hooks to override -----------------------------------------------------
107 * The actual drop has occurred. Calls <code>drop(Object target, DropTargetEvent event)
109 * @see DropTargetListener#drop(org.eclipse.swt.dnd.DropTargetEvent)
111 public void drop(DropTargetEvent event) {
112 drop(fTarget, event);
116 * The actual drop has occurred.
117 * @param target the drop target in form of a domain element.
118 * @param event the drop traget event
120 public void drop(Object target, DropTargetEvent event) {
124 * Checks if the drop is valid. The method calls <code>validateDrop
125 * (Object target, DropTargetEvent event). Implementors can alter the
126 * <code>currentDataType</code> field and the <code>detail</code> field
127 * to give feedback about drop acceptence.
129 public void validateDrop(DropTargetEvent event) {
130 validateDrop(fTarget, event, fRequestedOperation);
134 * Checks if the drop on the current target is valid. The method
135 * can alter the <code>currentDataType</code> field and the <code>
136 * detail</code> field to give feedback about drop acceptence.
137 * @param target the drop target in form of a domain element.
138 * @param event the drop traget event
139 * @param operation the operation requested by the user.
141 public void validateDrop(Object target, DropTargetEvent event, int operation) {
144 public void dragEnter(DropTargetEvent event) {
145 dragOperationChanged(event);
148 public void dragLeave(DropTargetEvent event) {
150 fLocation= LOCATION_NONE;
153 public void dragOperationChanged(DropTargetEvent event) {
154 fRequestedOperation= event.detail;
155 fTarget= computeTarget(event);
156 fLocation= computeLocation(event);
158 fLastOperation= event.detail;
159 computeFeedback(event);
162 public void dragOver(DropTargetEvent event) {
163 Object oldTarget= fTarget;
164 fTarget= computeTarget(event);
166 //set the location feedback
167 int oldLocation= fLocation;
168 fLocation= computeLocation(event);
169 if (oldLocation != fLocation || oldTarget != fTarget || fLastOperation != event.detail) {
171 fLastOperation= event.detail;
173 event.detail= fLastOperation;
175 computeFeedback(event);
178 public void dropAccept(DropTargetEvent event) {
179 fTarget= computeTarget(event);
181 fLastOperation= event.detail;
185 * Returns the data held by <code>event.item</code>. Inside a viewer
186 * this corresponds to the items data model element.
188 protected Object computeTarget(DropTargetEvent event) {
189 return event.item == null ? null : event.item.getData();
193 * Returns the position of the given coordinates relative to the given target.
194 * The position is determined to be before, after, or on the item, based on
195 * some threshold value. The return value is one of the LOCATION_* constants
196 * defined in this class.
198 final protected int computeLocation(DropTargetEvent event) {
199 if (!(event.item instanceof Item))
200 return LOCATION_NONE;
202 Item item= (Item) event.item;
203 Point coordinates= fViewer.getControl().toControl(new Point(event.x, event.y));
204 Rectangle bounds= getBounds(item);
205 if (bounds == null) {
206 return LOCATION_NONE;
208 if ((coordinates.y - bounds.y) < LOCATION_EPSILON) {
209 return LOCATION_BEFORE;
211 if ((bounds.y + bounds.height - coordinates.y) < LOCATION_EPSILON) {
212 return LOCATION_AFTER;
218 * Returns the bounds of the given item, or <code>null</code> if it is not a
219 * valid type of item.
221 private Rectangle getBounds(Item item) {
222 if (item instanceof TreeItem)
223 return ((TreeItem) item).getBounds();
225 if (item instanceof TableItem)
226 return ((TableItem) item).getBounds(0);
232 * Sets the drag under feedback corresponding to the value of <code>fLocation</code>
233 * and the <code>INSERTION_FEEDBACK</code> style bit.
235 protected void computeFeedback(DropTargetEvent event) {
236 if (!fShowInsertionFeedback && fLocation != LOCATION_NONE) {
237 event.feedback= DND.FEEDBACK_SELECT;
239 if (fLocation == LOCATION_BEFORE) {
240 event.feedback= DND.FEEDBACK_INSERT_BEFORE;
241 } else if (fLocation == LOCATION_AFTER) {
242 event.feedback= DND.FEEDBACK_INSERT_AFTER;
245 event.feedback|= fFeedback;
249 * Sets the drop operation to </code>DROP_NODE<code>.
251 protected void clearDropOperation(DropTargetEvent event) {
252 event.detail= DND.DROP_NONE;
256 * Returns the requested drop operation.
258 protected int getRequestedOperation() {
259 return fRequestedOperation;