7e2143be8a01cf362d4395b77502f6839df587b6
[phpeclipse.git] / net.sourceforge.phpeclipse.ui / src / net / sourceforge / phpdt / internal / ui / dnd / JdtViewerDropAdapter.java
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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.ui.dnd;
12
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;
23
24 /**
25  * A drag and drop adapter to be used together with structured viewers. The
26  * adapater delegates the <code>dragEnter</code>, <code>dragOperationChanged
27  * </code>,
28  * <code>dragOver</code> and <code>dropAccept</code> method to the
29  * <code>validateDrop</code> method. Furthermore it adds location feedback.
30  */
31 public class JdtViewerDropAdapter implements DropTargetListener {
32
33         /**
34          * Constant describing the position of the mouse cursor relative to the
35          * target object. This means the mouse is positioned slightly before the
36          * target.
37          */
38         protected static final int LOCATION_BEFORE = 1;
39
40         /**
41          * Constant describing the position of the mouse cursor relative to the
42          * target object. This means the mouse is positioned slightly after the
43          * target.
44          */
45         protected static final int LOCATION_AFTER = 2;
46
47         /**
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.
50          */
51         protected static final int LOCATION_ON = 3;
52
53         /**
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
56          * valid target.
57          */
58         protected static final int LOCATION_NONE = 4;
59
60         /**
61          * The threshold used to determine if the mouse is before or after an item.
62          */
63         private static final int LOCATION_EPSILON = 5;
64
65         /**
66          * Style to enable location feedback.
67          */
68         public static final int INSERTION_FEEDBACK = 1 << 1;
69
70         private StructuredViewer fViewer;
71
72         private int fFeedback;
73
74         private boolean fShowInsertionFeedback;
75
76         private int fRequestedOperation;
77
78         private int fLastOperation;
79
80         protected int fLocation;
81
82         protected Object fTarget;
83
84         public JdtViewerDropAdapter(StructuredViewer viewer, int feedback) {
85                 fViewer = viewer;
86                 Assert.isNotNull(fViewer);
87                 fFeedback = feedback;
88                 fLastOperation = -1;
89         }
90
91         /**
92          * Controls whether the drop adapter shows insertion feedback or not.
93          * 
94          * @param showInsertionFeedback
95          *            <code>true</code> if the drop adapter is supposed to show
96          *            insertion feedback. Otherwise <code>false</code>
97          */
98         public void showInsertionFeedback(boolean showInsertionFeedback) {
99                 fShowInsertionFeedback = showInsertionFeedback;
100         }
101
102         /**
103          * Returns the viewer this adapter is working on.
104          */
105         protected StructuredViewer getViewer() {
106                 return fViewer;
107         }
108
109         // ---- Hooks to override
110         // -----------------------------------------------------
111
112         /**
113          * The actual drop has occurred. Calls
114          * <code>drop(Object target, DropTargetEvent event)
115          * </code>.
116          * 
117          * @see DropTargetListener#drop(org.eclipse.swt.dnd.DropTargetEvent)
118          */
119         public void drop(DropTargetEvent event) {
120                 drop(fTarget, event);
121         }
122
123         /**
124          * The actual drop has occurred.
125          * 
126          * @param target
127          *            the drop target in form of a domain element.
128          * @param event
129          *            the drop traget event
130          */
131         public void drop(Object target, DropTargetEvent event) {
132         }
133
134         /**
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.
139          */
140         public void validateDrop(DropTargetEvent event) {
141                 validateDrop(fTarget, event, fRequestedOperation);
142         }
143
144         /**
145          * Checks if the drop on the current target is valid. The method can alter
146          * the <code>currentDataType</code> field and the <code>
147          * detail</code>
148          * field to give feedback about drop acceptence.
149          * 
150          * @param target
151          *            the drop target in form of a domain element.
152          * @param event
153          *            the drop traget event
154          * @param operation
155          *            the operation requested by the user.
156          */
157         public void validateDrop(Object target, DropTargetEvent event, int operation) {
158         }
159
160         public void dragEnter(DropTargetEvent event) {
161                 dragOperationChanged(event);
162         }
163
164         public void dragLeave(DropTargetEvent event) {
165                 fTarget = null;
166                 fLocation = LOCATION_NONE;
167         }
168
169         public void dragOperationChanged(DropTargetEvent event) {
170                 fRequestedOperation = event.detail;
171                 fTarget = computeTarget(event);
172                 fLocation = computeLocation(event);
173                 validateDrop(event);
174                 fLastOperation = event.detail;
175                 computeFeedback(event);
176         }
177
178         public void dragOver(DropTargetEvent event) {
179                 Object oldTarget = fTarget;
180                 fTarget = computeTarget(event);
181
182                 // set the location feedback
183                 int oldLocation = fLocation;
184                 fLocation = computeLocation(event);
185                 if (oldLocation != fLocation || oldTarget != fTarget
186                                 || fLastOperation != event.detail) {
187                         validateDrop(event);
188                         fLastOperation = event.detail;
189                 } else {
190                         event.detail = fLastOperation;
191                 }
192                 computeFeedback(event);
193         }
194
195         public void dropAccept(DropTargetEvent event) {
196                 fTarget = computeTarget(event);
197                 validateDrop(event);
198                 fLastOperation = event.detail;
199         }
200
201         /**
202          * Returns the data held by <code>event.item</code>. Inside a viewer this
203          * corresponds to the items data model element.
204          */
205         protected Object computeTarget(DropTargetEvent event) {
206                 return event.item == null ? null : event.item.getData();
207         }
208
209         /**
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.
214          */
215         final protected int computeLocation(DropTargetEvent event) {
216                 if (!(event.item instanceof Item))
217                         return LOCATION_NONE;
218
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;
225                 }
226                 if ((coordinates.y - bounds.y) < LOCATION_EPSILON) {
227                         return LOCATION_BEFORE;
228                 }
229                 if ((bounds.y + bounds.height - coordinates.y) < LOCATION_EPSILON) {
230                         return LOCATION_AFTER;
231                 }
232                 return LOCATION_ON;
233         }
234
235         /**
236          * Returns the bounds of the given item, or <code>null</code> if it is not
237          * a valid type of item.
238          */
239         private Rectangle getBounds(Item item) {
240                 if (item instanceof TreeItem)
241                         return ((TreeItem) item).getBounds();
242
243                 if (item instanceof TableItem)
244                         return ((TableItem) item).getBounds(0);
245
246                 return null;
247         }
248
249         /**
250          * Sets the drag under feedback corresponding to the value of
251          * <code>fLocation</code> and the <code>INSERTION_FEEDBACK</code> style
252          * bit.
253          */
254         protected void computeFeedback(DropTargetEvent event) {
255                 if (!fShowInsertionFeedback && fLocation != LOCATION_NONE) {
256                         event.feedback = DND.FEEDBACK_SELECT;
257                 } else {
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;
262                         }
263                 }
264                 event.feedback |= fFeedback;
265         }
266
267         /**
268          * Sets the drop operation to </code>DROP_NODE<code>.
269          */
270         protected void clearDropOperation(DropTargetEvent event) {
271                 event.detail = DND.DROP_NONE;
272         }
273
274         /**
275          * Returns the requested drop operation.
276          */
277         protected int getRequestedOperation() {
278                 return fRequestedOperation;
279         }
280 }