migrated plugin from 3.0 to 3.1
[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 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.
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.
29  */
30 public class JdtViewerDropAdapter implements DropTargetListener {
31
32         /**
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.
36          */
37         protected static final int LOCATION_BEFORE= 1;
38         
39         /**
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.
43          */
44         protected static final int LOCATION_AFTER= 2;
45         
46         /**
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.
50          */
51         protected static final int LOCATION_ON= 3;
52         
53         /**
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.
57          */
58         protected static final int LOCATION_NONE= 4;
59         
60         /**
61          * The threshold used to determine if the mouse is before or after
62          * an item.
63          */
64         private static final int LOCATION_EPSILON= 5; 
65         
66         /**
67          * Style to enable location feedback.
68          */
69         public static final int INSERTION_FEEDBACK= 1 << 1; 
70
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;
78
79         public JdtViewerDropAdapter(StructuredViewer viewer, int feedback) {
80                 fViewer= viewer;
81                 Assert.isNotNull(fViewer);
82                 fFeedback= feedback;
83                 fLastOperation= -1;
84         }
85
86         /**
87          * Controls whether the drop adapter shows insertion feedback or not.
88          * 
89          * @param showInsertionFeedback <code>true</code> if the drop adapter is supposed
90          *      to show insertion feedback. Otherwise <code>false</code>
91          */
92         public void showInsertionFeedback(boolean showInsertionFeedback) {
93                 fShowInsertionFeedback= showInsertionFeedback;
94         }
95         
96         /**
97          * Returns the viewer this adapter is working on.
98          */
99         protected StructuredViewer getViewer() {
100                 return fViewer;
101         } 
102         
103         //---- Hooks to override -----------------------------------------------------
104         
105         /**
106          * The actual drop has occurred. Calls <code>drop(Object target, DropTargetEvent event)
107          * </code>.
108          * @see DropTargetListener#drop(org.eclipse.swt.dnd.DropTargetEvent)
109          */      
110         public void drop(DropTargetEvent event) {
111                 drop(fTarget, event);
112         }
113         
114         /**
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
118          */      
119         public void drop(Object target, DropTargetEvent event) {
120         }
121         
122         /**
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.
127          */
128         public void validateDrop(DropTargetEvent event) {
129                 validateDrop(fTarget, event, fRequestedOperation);
130         }
131         
132         /**
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.
139          */
140         public void validateDrop(Object target, DropTargetEvent event, int operation) {
141         }
142         
143         public void dragEnter(DropTargetEvent event) {
144                 dragOperationChanged(event);
145         }
146         
147         public void dragLeave(DropTargetEvent event) {
148                 fTarget= null;
149                 fLocation= LOCATION_NONE;
150         }
151         
152         public void dragOperationChanged(DropTargetEvent event) {
153                 fRequestedOperation= event.detail;
154                 fTarget= computeTarget(event);
155                 fLocation= computeLocation(event);
156                 validateDrop(event);
157                 fLastOperation= event.detail;
158                 computeFeedback(event);
159         }
160         
161         public void dragOver(DropTargetEvent event) {
162                 Object oldTarget= fTarget;
163                 fTarget= computeTarget(event);
164                 
165                 //set the location feedback
166                 int oldLocation= fLocation;
167                 fLocation= computeLocation(event);
168                 if (oldLocation != fLocation || oldTarget != fTarget || fLastOperation != event.detail) {
169                         validateDrop(event);
170                         fLastOperation= event.detail;
171                 } else {
172                         event.detail= fLastOperation;
173                 }
174                 computeFeedback(event);
175         }
176         
177         public void dropAccept(DropTargetEvent event) {
178                 fTarget= computeTarget(event);
179                 validateDrop(event);
180                 fLastOperation= event.detail;
181         }
182         
183         /**
184          * Returns the data held by <code>event.item</code>. Inside a viewer
185          * this corresponds to the items data model element.
186          */
187         protected Object computeTarget(DropTargetEvent event) {
188                 return event.item == null ? null : event.item.getData();
189         }
190         
191         /**
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.
196          */
197         final protected int computeLocation(DropTargetEvent event) {
198                 if (!(event.item instanceof Item))
199                         return LOCATION_NONE;
200                 
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;
206                 }
207                 if ((coordinates.y - bounds.y) < LOCATION_EPSILON) {
208                         return LOCATION_BEFORE;
209                 }
210                 if ((bounds.y + bounds.height - coordinates.y) < LOCATION_EPSILON) {
211                         return LOCATION_AFTER;
212                 }
213                 return LOCATION_ON;
214         }
215
216         /**
217          * Returns the bounds of the given item, or <code>null</code> if it is not a 
218          * valid type of item.
219          */
220         private Rectangle getBounds(Item item) {
221                 if (item instanceof TreeItem)
222                         return ((TreeItem) item).getBounds();
223                         
224                 if (item instanceof TableItem)
225                         return ((TableItem) item).getBounds(0);
226                         
227                 return null;
228         }
229
230         /**
231          * Sets the drag under feedback corresponding to the value of <code>fLocation</code>
232          * and the <code>INSERTION_FEEDBACK</code> style bit.
233          */
234         protected void computeFeedback(DropTargetEvent event) {
235                 if (!fShowInsertionFeedback && fLocation != LOCATION_NONE) {
236                         event.feedback= DND.FEEDBACK_SELECT;
237                 } else {
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;
242                         }
243                 }
244                 event.feedback|= fFeedback;
245         }
246         
247         /**
248          * Sets the drop operation to </code>DROP_NODE<code>.
249          */
250         protected void clearDropOperation(DropTargetEvent event) {
251                 event.detail= DND.DROP_NONE;
252         }
253         
254         /**
255          * Returns the requested drop operation.
256          */
257         protected int getRequestedOperation() {
258                 return fRequestedOperation;
259         } 
260 }