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