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.
26 * The adapater delegates the <code>dragEnter</code>, <code>dragOperationChanged
27 * </code>, <code>dragOver</code> and <code>dropAccept</code> method to the
28 * <code>validateDrop</code> method. Furthermore it adds location feedback.
30 public class JdtViewerDropAdapter implements DropTargetListener {
33 * Constant describing the position of the mouse cursor relative
34 * to the target object. This means the mouse is positioned
35 * slightly before the target.
37 protected static final int LOCATION_BEFORE= 1;
40 * Constant describing the position of the mouse cursor relative
41 * to the target object. This means the mouse is positioned
42 * slightly after the target.
44 protected static final int LOCATION_AFTER= 2;
47 * Constant describing the position of the mouse cursor relative
48 * to the target object. This means the mouse is positioned
49 * directly on the target.
51 protected static final int LOCATION_ON= 3;
54 * Constant describing the position of the mouse cursor relative
55 * to the target object. This means the mouse is not positioned
56 * over or near any valid target.
58 protected static final int LOCATION_NONE= 4;
61 * The threshold used to determine if the mouse is before or after
64 private static final int LOCATION_EPSILON= 5;
67 * Style to enable location feedback.
69 public static final int INSERTION_FEEDBACK= 1 << 1;
71 private StructuredViewer fViewer;
72 private int fFeedback;
73 private boolean fShowInsertionFeedback;
74 private int fRequestedOperation;
75 private int fLastOperation;
76 protected int fLocation;
77 protected Object fTarget;
79 public JdtViewerDropAdapter(StructuredViewer viewer, int feedback) {
81 Assert.isNotNull(fViewer);
87 * Controls whether the drop adapter shows insertion feedback or not.
89 * @param showInsertionFeedback <code>true</code> if the drop adapter is supposed
90 * to show insertion feedback. Otherwise <code>false</code>
92 public void showInsertionFeedback(boolean showInsertionFeedback) {
93 fShowInsertionFeedback= showInsertionFeedback;
97 * Returns the viewer this adapter is working on.
99 protected StructuredViewer getViewer() {
103 //---- Hooks to override -----------------------------------------------------
106 * The actual drop has occurred. Calls <code>drop(Object target, DropTargetEvent event)
108 * @see DropTargetListener#drop(org.eclipse.swt.dnd.DropTargetEvent)
110 public void drop(DropTargetEvent event) {
111 drop(fTarget, event);
115 * The actual drop has occurred.
116 * @param target the drop target in form of a domain element.
117 * @param event the drop traget event
119 public void drop(Object target, DropTargetEvent event) {
123 * Checks if the drop is valid. The method calls <code>validateDrop
124 * (Object target, DropTargetEvent event). Implementors can alter the
125 * <code>currentDataType</code> field and the <code>detail</code> field
126 * to give feedback about drop acceptence.
128 public void validateDrop(DropTargetEvent event) {
129 validateDrop(fTarget, event, fRequestedOperation);
133 * Checks if the drop on the current target is valid. The method
134 * can alter the <code>currentDataType</code> field and the <code>
135 * detail</code> field to give feedback about drop acceptence.
136 * @param target the drop target in form of a domain element.
137 * @param event the drop traget event
138 * @param operation the operation requested by the user.
140 public void validateDrop(Object target, DropTargetEvent event, int operation) {
143 public void dragEnter(DropTargetEvent event) {
144 dragOperationChanged(event);
147 public void dragLeave(DropTargetEvent event) {
149 fLocation= LOCATION_NONE;
152 public void dragOperationChanged(DropTargetEvent event) {
153 fRequestedOperation= event.detail;
154 fTarget= computeTarget(event);
155 fLocation= computeLocation(event);
157 fLastOperation= event.detail;
158 computeFeedback(event);
161 public void dragOver(DropTargetEvent event) {
162 Object oldTarget= fTarget;
163 fTarget= computeTarget(event);
165 //set the location feedback
166 int oldLocation= fLocation;
167 fLocation= computeLocation(event);
168 if (oldLocation != fLocation || oldTarget != fTarget || fLastOperation != event.detail) {
170 fLastOperation= event.detail;
172 event.detail= fLastOperation;
174 computeFeedback(event);
177 public void dropAccept(DropTargetEvent event) {
178 fTarget= computeTarget(event);
180 fLastOperation= event.detail;
184 * Returns the data held by <code>event.item</code>. Inside a viewer
185 * this corresponds to the items data model element.
187 protected Object computeTarget(DropTargetEvent event) {
188 return event.item == null ? null : event.item.getData();
192 * Returns the position of the given coordinates relative to the given target.
193 * The position is determined to be before, after, or on the item, based on
194 * some threshold value. The return value is one of the LOCATION_* constants
195 * defined in this class.
197 final protected int computeLocation(DropTargetEvent event) {
198 if (!(event.item instanceof Item))
199 return LOCATION_NONE;
201 Item item= (Item) event.item;
202 Point coordinates= fViewer.getControl().toControl(new Point(event.x, event.y));
203 Rectangle bounds= getBounds(item);
204 if (bounds == null) {
205 return LOCATION_NONE;
207 if ((coordinates.y - bounds.y) < LOCATION_EPSILON) {
208 return LOCATION_BEFORE;
210 if ((bounds.y + bounds.height - coordinates.y) < LOCATION_EPSILON) {
211 return LOCATION_AFTER;
217 * Returns the bounds of the given item, or <code>null</code> if it is not a
218 * valid type of item.
220 private Rectangle getBounds(Item item) {
221 if (item instanceof TreeItem)
222 return ((TreeItem) item).getBounds();
224 if (item instanceof TableItem)
225 return ((TableItem) item).getBounds(0);
231 * Sets the drag under feedback corresponding to the value of <code>fLocation</code>
232 * and the <code>INSERTION_FEEDBACK</code> style bit.
234 protected void computeFeedback(DropTargetEvent event) {
235 if (!fShowInsertionFeedback && fLocation != LOCATION_NONE) {
236 event.feedback= DND.FEEDBACK_SELECT;
238 if (fLocation == LOCATION_BEFORE) {
239 event.feedback= DND.FEEDBACK_INSERT_BEFORE;
240 } else if (fLocation == LOCATION_AFTER) {
241 event.feedback= DND.FEEDBACK_INSERT_AFTER;
244 event.feedback|= fFeedback;
248 * Sets the drop operation to </code>DROP_NODE<code>.
250 protected void clearDropOperation(DropTargetEvent event) {
251 event.detail= DND.DROP_NONE;
255 * Returns the requested drop operation.
257 protected int getRequestedOperation() {
258 return fRequestedOperation;