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.jface.util.Assert;
14 import org.eclipse.jface.viewers.StructuredViewer;
15 import org.eclipse.swt.dnd.DND;
16 import org.eclipse.swt.dnd.DropTargetEvent;
17 import org.eclipse.swt.dnd.DropTargetListener;
18 import org.eclipse.swt.graphics.Point;
19 import org.eclipse.swt.graphics.Rectangle;
20 import org.eclipse.swt.widgets.Item;
21 import org.eclipse.swt.widgets.TableItem;
22 import org.eclipse.swt.widgets.TreeItem;
25 * A drag and drop adapter to be used together with structured viewers. The
26 * adapater delegates the <code>dragEnter</code>, <code>dragOperationChanged
28 * <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 to the
35 * target object. This means the mouse is positioned slightly before the
38 protected static final int LOCATION_BEFORE = 1;
41 * Constant describing the position of the mouse cursor relative to the
42 * target object. This means the mouse is positioned slightly after the
45 protected static final int LOCATION_AFTER = 2;
48 * Constant describing the position of the mouse cursor relative to the
49 * target object. This means the mouse is positioned directly on the target.
51 protected static final int LOCATION_ON = 3;
54 * Constant describing the position of the mouse cursor relative to the
55 * target object. This means the mouse is not positioned over or near any
58 protected static final int LOCATION_NONE = 4;
61 * The threshold used to determine if the mouse is before or after an item.
63 private static final int LOCATION_EPSILON = 5;
66 * Style to enable location feedback.
68 public static final int INSERTION_FEEDBACK = 1 << 1;
70 private StructuredViewer fViewer;
72 private int fFeedback;
74 private boolean fShowInsertionFeedback;
76 private int fRequestedOperation;
78 private int fLastOperation;
80 protected int fLocation;
82 protected Object fTarget;
84 public JdtViewerDropAdapter(StructuredViewer viewer, int feedback) {
86 Assert.isNotNull(fViewer);
92 * Controls whether the drop adapter shows insertion feedback or not.
94 * @param showInsertionFeedback
95 * <code>true</code> if the drop adapter is supposed to show
96 * insertion feedback. Otherwise <code>false</code>
98 public void showInsertionFeedback(boolean showInsertionFeedback) {
99 fShowInsertionFeedback = showInsertionFeedback;
103 * Returns the viewer this adapter is working on.
105 protected StructuredViewer getViewer() {
109 // ---- Hooks to override
110 // -----------------------------------------------------
113 * The actual drop has occurred. Calls
114 * <code>drop(Object target, DropTargetEvent event)
117 * @see DropTargetListener#drop(org.eclipse.swt.dnd.DropTargetEvent)
119 public void drop(DropTargetEvent event) {
120 drop(fTarget, event);
124 * The actual drop has occurred.
127 * the drop target in form of a domain element.
129 * the drop traget event
131 public void drop(Object target, DropTargetEvent event) {
135 * Checks if the drop is valid. The method calls <code>validateDrop
136 * (Object target, DropTargetEvent event). Implementors can alter the
137 * <code>currentDataType</code> field and the <code>detail</code> field
138 * to give feedback about drop acceptence.
140 public void validateDrop(DropTargetEvent event) {
141 validateDrop(fTarget, event, fRequestedOperation);
145 * Checks if the drop on the current target is valid. The method can alter
146 * the <code>currentDataType</code> field and the <code>
148 * field to give feedback about drop acceptence.
151 * the drop target in form of a domain element.
153 * the drop traget event
155 * the operation requested by the user.
157 public void validateDrop(Object target, DropTargetEvent event, int operation) {
160 public void dragEnter(DropTargetEvent event) {
161 dragOperationChanged(event);
164 public void dragLeave(DropTargetEvent event) {
166 fLocation = LOCATION_NONE;
169 public void dragOperationChanged(DropTargetEvent event) {
170 fRequestedOperation = event.detail;
171 fTarget = computeTarget(event);
172 fLocation = computeLocation(event);
174 fLastOperation = event.detail;
175 computeFeedback(event);
178 public void dragOver(DropTargetEvent event) {
179 Object oldTarget = fTarget;
180 fTarget = computeTarget(event);
182 // set the location feedback
183 int oldLocation = fLocation;
184 fLocation = computeLocation(event);
185 if (oldLocation != fLocation || oldTarget != fTarget
186 || fLastOperation != event.detail) {
188 fLastOperation = event.detail;
190 event.detail = fLastOperation;
192 computeFeedback(event);
195 public void dropAccept(DropTargetEvent event) {
196 fTarget = computeTarget(event);
198 fLastOperation = event.detail;
202 * Returns the data held by <code>event.item</code>. Inside a viewer this
203 * corresponds to the items data model element.
205 protected Object computeTarget(DropTargetEvent event) {
206 return event.item == null ? null : event.item.getData();
210 * Returns the position of the given coordinates relative to the given
211 * target. The position is determined to be before, after, or on the item,
212 * based on some threshold value. The return value is one of the LOCATION_*
213 * constants defined in this class.
215 final protected int computeLocation(DropTargetEvent event) {
216 if (!(event.item instanceof Item))
217 return LOCATION_NONE;
219 Item item = (Item) event.item;
220 Point coordinates = fViewer.getControl().toControl(
221 new Point(event.x, event.y));
222 Rectangle bounds = getBounds(item);
223 if (bounds == null) {
224 return LOCATION_NONE;
226 if ((coordinates.y - bounds.y) < LOCATION_EPSILON) {
227 return LOCATION_BEFORE;
229 if ((bounds.y + bounds.height - coordinates.y) < LOCATION_EPSILON) {
230 return LOCATION_AFTER;
236 * Returns the bounds of the given item, or <code>null</code> if it is not
237 * a valid type of item.
239 private Rectangle getBounds(Item item) {
240 if (item instanceof TreeItem)
241 return ((TreeItem) item).getBounds();
243 if (item instanceof TableItem)
244 return ((TableItem) item).getBounds(0);
250 * Sets the drag under feedback corresponding to the value of
251 * <code>fLocation</code> and the <code>INSERTION_FEEDBACK</code> style
254 protected void computeFeedback(DropTargetEvent event) {
255 if (!fShowInsertionFeedback && fLocation != LOCATION_NONE) {
256 event.feedback = DND.FEEDBACK_SELECT;
258 if (fLocation == LOCATION_BEFORE) {
259 event.feedback = DND.FEEDBACK_INSERT_BEFORE;
260 } else if (fLocation == LOCATION_AFTER) {
261 event.feedback = DND.FEEDBACK_INSERT_AFTER;
264 event.feedback |= fFeedback;
268 * Sets the drop operation to </code>DROP_NODE<code>.
270 protected void clearDropOperation(DropTargetEvent event) {
271 event.detail = DND.DROP_NONE;
275 * Returns the requested drop operation.
277 protected int getRequestedOperation() {
278 return fRequestedOperation;