KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > TrimDropTarget


1 /*******************************************************************************
2  * Copyright (c) 2004, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.ui.internal;
12
13 import java.util.Iterator JavaDoc;
14 import java.util.List JavaDoc;
15
16 import org.eclipse.jface.util.Geometry;
17 import org.eclipse.swt.SWT;
18 import org.eclipse.swt.graphics.Cursor;
19 import org.eclipse.swt.graphics.Point;
20 import org.eclipse.swt.graphics.Rectangle;
21 import org.eclipse.swt.widgets.Composite;
22 import org.eclipse.swt.widgets.Control;
23 import org.eclipse.ui.internal.dnd.DragBorder;
24 import org.eclipse.ui.internal.dnd.DragUtil;
25 import org.eclipse.ui.internal.dnd.IDragOverListener;
26 import org.eclipse.ui.internal.dnd.IDropTarget;
27 import org.eclipse.ui.internal.dnd.IDropTarget2;
28 import org.eclipse.ui.internal.layout.IWindowTrim;
29 import org.eclipse.ui.internal.layout.LayoutUtil;
30 import org.eclipse.ui.internal.layout.TrimDescriptor;
31 import org.eclipse.ui.internal.layout.TrimLayout;
32 import org.eclipse.ui.internal.layout.TrimToolBarBase;
33
34 /**
35  */

36 /*package*/class TrimDropTarget implements IDragOverListener {
37     
38     private final class ActualTrimDropTarget implements IDropTarget2 {
39         public IWindowTrim draggedTrim;
40         
41         // tracking parameters
42
private DragBorder border = null;
43         private int dockedArea;
44         
45         // Holder for the position of trim that is 'floating' with the cursor
46
private int cursorAreaId;
47         private int initialAreaId;
48         private IWindowTrim initialInsertBefore;
49         private Rectangle initialLocation;
50
51         /**
52          * Constructor
53          */

54         private ActualTrimDropTarget() {
55             super();
56
57             draggedTrim = null;
58             dockedArea = SWT.NONE;
59             
60             initialAreaId = SWT.NONE;
61             initialInsertBefore = null;
62         }
63         
64         /**
65          * This method is used to delineate separate trims dragging events. The -first- drag
66          * event will set this and then it will remain constant until the drag gesture is done;
67          * either by dropping or escaping. Once the gesture is finished the trim value is set
68          * back to 'null'.
69          *
70          * @param trim The trim item currently being dragged.
71          */

72         public void startDrag(IWindowTrim trim) {
73             // Are we starting a new drag?
74
if (draggedTrim != trim) {
75                 // remember the dragged trim
76
draggedTrim = trim;
77                 
78                 // Remember the location that we were in initially so we
79
// can go back there on an cancel...
80
initialAreaId = layout.getTrimAreaId(draggedTrim.getControl());
81                 
82                 // Determine who we were placed 'before' in the trim
83
initialInsertBefore = getInsertBefore(initialAreaId, draggedTrim);
84                 
85                 // Remember the location that the control used to be at for animation purposes
86
initialLocation = DragUtil.getDisplayBounds(draggedTrim.getControl());
87                                 
88                 // The dragged trim is always initially docked
89
dockedArea = initialAreaId;
90             }
91         }
92                 
93         /**
94          * Determine the trim area from the point. To avoid clashing at the 'corners' due to extending the trim area's
95          * rectangles we first ensure that the point is not actually -within- a trim area before we check the extended
96          * rectangles.
97          *
98          * @param pos The current cursor pos
99          * @return the Trim area that the cursor is in or SWT.NONE if the point is not in an area
100          */

101         private int getTrimArea(Point pos) {
102             // First, check if we're actually -within- a trim area (i.e. no boundary extensions)
103
int areaId = getTrimArea(pos, 0);
104             
105             // If we are not inside a trim area...are we 'close' to one?
106
if (areaId == SWT.NONE) {
107                 areaId = getTrimArea(pos, TrimDragPreferences.getThreshold());
108             }
109             
110             // not inside any trim area
111
return areaId;
112         }
113         
114         /**
115          * Checks the trims areas against the given position. Each trim area is 'extended' into
116          * the workbench page by the value of <code>extendedBoundaryWidth</code> before the checking
117          * takes place.
118          *
119          * @param pos The point to check against
120          * @param extendedBoundaryWidth The amount to extend the trim area's 'inner' edge by
121          *
122          * @return The trim area or SWT.NONE if the point is not within any extended trim area's rect.
123          */

124         private int getTrimArea(Point pos, int extendedBoundaryWidth) {
125             int[] areaIds = layout.getAreaIds();
126             for (int i = 0; i < areaIds.length; i++) {
127                 Rectangle trimRect = layout.getTrimRect(windowComposite, areaIds[i]);
128                 trimRect = Geometry.toControl(windowComposite, trimRect);
129
130                 // Only check 'valid' sides
131
if ( (areaIds[i] & getValidSides()) != SWT.NONE) {
132                     // TODO: more confusion binding 'areaIds' to SWT 'sides'
133
switch (areaIds[i]) {
134                     case SWT.LEFT:
135                         trimRect.width += extendedBoundaryWidth;
136                         
137                         if (pos.y >= trimRect.y &&
138                             pos.y <= (trimRect.y+trimRect.height) &&
139                             pos.x <= (trimRect.x+trimRect.width)) {
140                             return areaIds[i];
141                         }
142                         break;
143                     case SWT.RIGHT:
144                         trimRect.x -= extendedBoundaryWidth;
145                         trimRect.width += extendedBoundaryWidth;
146                         
147                         if (pos.y >= trimRect.y &&
148                             pos.y <= (trimRect.y+trimRect.height) &&
149                             pos.x >= trimRect.x) {
150                             return areaIds[i];
151                         }
152                         break;
153                     case SWT.TOP:
154                         trimRect.height += extendedBoundaryWidth;
155                         
156                         if (pos.x >= trimRect.x &&
157                             pos.x <= (trimRect.x+trimRect.width) &&
158                             pos.y <= (trimRect.y+trimRect.height)) {
159                             return areaIds[i];
160                         }
161                         break;
162                     case SWT.BOTTOM:
163                         trimRect.y -= extendedBoundaryWidth;
164                         trimRect.height += extendedBoundaryWidth;
165                         
166                         if (pos.x >= trimRect.x &&
167                             pos.x <= (trimRect.x+trimRect.width) &&
168                             pos.y >= trimRect.y) {
169                             return areaIds[i];
170                         }
171                         break;
172                     }
173                 }
174             }
175             
176             // not inside any trim area
177
return SWT.NONE;
178         }
179         
180         /**
181          * Determine the window trim that the currently dragged trim should be inserted
182          * before.
183          * @param areaId The area id that is being checked
184          * @param pos The position used to determine the correct insertion trim
185          * @return The trim to 'dock' the draggedTrim before
186          */

187         private IWindowTrim getInsertBefore(int areaId, Point pos) {
188             boolean isHorizontal = (areaId == SWT.TOP) || (areaId == SWT.BOTTOM);
189             
190             // Walk the trim area and return the first one that the positon
191
// is 'after'.
192
List JavaDoc tDescs = layout.getTrimArea(areaId).getDescriptors();
193             for (Iterator JavaDoc iter = tDescs.iterator(); iter.hasNext();) {
194                 TrimDescriptor desc = (TrimDescriptor) iter.next();
195                 
196                 // Skip ourselves
197
if (desc.getTrim() == draggedTrim) {
198                     continue;
199                 }
200                 
201                 // Now, check
202
Rectangle bb = desc.getCache().getControl().getBounds();
203                 Point center = Geometry.centerPoint(bb);
204                 if (isHorizontal) {
205                     if (pos.x < center.x) {
206                         return desc.getTrim();
207                     }
208                 }
209                 else {
210                     if (pos.y < center.y) {
211                         return desc.getTrim();
212                     }
213                 }
214             }
215             
216             return null;
217         }
218         
219         /**
220          * Returns the trim that is 'before' the given trim in the given area
221          *
222          * @param areaId The areaId of the trim
223          * @param trim The trim to find the element after
224          *
225          * @return The trim that the given trim is 'before'
226          */

227         private IWindowTrim getInsertBefore(int areaId, IWindowTrim trim) {
228             List JavaDoc tDescs = layout.getTrimArea(areaId).getDescriptors();
229             for (Iterator JavaDoc iter = tDescs.iterator(); iter.hasNext();) {
230                 TrimDescriptor desc = (TrimDescriptor) iter.next();
231                 if (desc.getTrim() == trim) {
232                     if (iter.hasNext()) {
233                         desc = (TrimDescriptor) iter.next();
234                         return desc.getTrim();
235                     }
236                     return null;
237                 }
238             }
239             
240             return null;
241         }
242         
243         /**
244          * Recalculates the drop information based on the current cursor pos.
245          *
246          * @param pos The cursor position
247          */

248         public void track(Point pos) {
249             // Convert the mouse positon into 'local' coords
250
Rectangle r = new Rectangle(pos.x, pos.y, 1,1);
251             r = Geometry.toControl(windowComposite, r);
252             pos.x = r.x;
253             pos.y = r.y;
254                         
255             // Are we 'inside' a trim area ?
256
cursorAreaId = getTrimArea(pos);
257
258             // Provide tracking for the appropriate 'mode'
259
if (cursorAreaId != SWT.NONE) {
260                 trackInsideTrimArea(pos);
261             } else {
262                 trackOutsideTrimArea(pos);
263             }
264         }
265        
266         /**
267          * Perform the feedback used when the cursor is 'inside' a particular trim area.
268          * The current implementation will place the dragged trim into the trim area at
269          * the location determined by the supplied point.
270          *
271          * @param pos The point to use to determine where in the trim area the dragged trim
272          * should be located.
273          */

274         private void trackInsideTrimArea(Point pos) {
275             // Where should we be?
276
int newArea = getTrimArea(pos);
277             IWindowTrim newInsertBefore = getInsertBefore(newArea, pos);
278
279             // if we're currently undocked then we should dock
280
boolean shouldDock = dockedArea == SWT.NONE;
281             
282             // If we're already docked then only update if there's a change in area or position
283
if (dockedArea != SWT.NONE) {
284                 // Where are we now?
285
IWindowTrim curInsertBefore = getInsertBefore(dockedArea, draggedTrim);
286                 
287                 // If we're already docked we should only update if there's a change
288
shouldDock = dockedArea != newArea || curInsertBefore != newInsertBefore;
289             }
290             
291             // Do we have to do anything?
292
if (shouldDock) {
293                 // (Re)dock the trim in the new location
294
dock(newArea, newInsertBefore);
295             }
296         }
297         
298         /**
299          * Provide the dragging feedback when the cursor is -not- explicitly inside
300          * a particular trim area.
301          *
302          */

303         private void trackOutsideTrimArea(Point pos) {
304             // If we -were- docked then undock
305
if (dockedArea != SWT.NONE) {
306                 undock();
307             }
308             
309             border.setLocation(pos, SWT.BOTTOM);
310         }
311                 
312         /**
313          * Return the set of valid sides that a piece of trim can be docked on. We
314          * arbitrarily extend this to include any areas that won't cause a change in orientation
315          *
316          * @return The extended drop 'side' set
317          */

318         private int getValidSides() {
319             int result = draggedTrim.getValidSides();
320             if (result == SWT.NONE) {
321                 return result;
322             }
323
324             // For now, if we can dock...we can dock -anywhere-
325
return SWT.TOP | SWT.BOTTOM | SWT.LEFT | SWT.RIGHT;
326         }
327
328         /**
329          * The user either cancelled the drag or tried to drop the trim in an invalid
330          * area...put the trim back in the last location it was in
331          */

332         private void redock() {
333             // Since the control might move 'far' we'll provide an animation
334
Rectangle startRect = DragUtil.getDisplayBounds(draggedTrim.getControl());
335             RectangleAnimation animation = new RectangleAnimation(
336                     windowComposite.getShell(), startRect, initialLocation, 300);
337             animation.schedule();
338
339             dock(initialAreaId, initialInsertBefore);
340         }
341         
342         /* (non-Javadoc)
343          * @see org.eclipse.ui.internal.dnd.IDropTarget#drop()
344          */

345         public void drop() {
346             // If we aren't docked then restore the initial location
347
if (dockedArea == SWT.NONE) {
348                 redock();
349             }
350         }
351
352         /**
353          * Remove the trim frmo its current 'docked' location and attach it
354          * to the cursor...
355          */

356         private void undock() {
357             // Remove the trim from the layout
358
layout.removeTrim(draggedTrim);
359             LayoutUtil.resize(draggedTrim.getControl());
360             
361             // Re-orient the widget to its -original- side and size
362
draggedTrim.dock(initialAreaId);
363             draggedTrim.getControl().setSize(initialLocation.width, initialLocation.height);
364             
365             // Create a new dragging border onto the dragged trim
366
// Special check for TrimPart...should be generalized
367
boolean wantsFrame = !(draggedTrim instanceof TrimToolBarBase);
368             border = new DragBorder(windowComposite, draggedTrim.getControl(), wantsFrame);
369
370             dockedArea = SWT.NONE;
371         }
372         
373         /**
374          * Return the 'undocked' trim to its previous location in the layout
375          */

376         private void dock(int areaId, IWindowTrim insertBefore) {
377             // remove the drag 'border'
378
if (border != null) {
379                 border.dispose();
380                 border = null;
381             }
382             
383             // Update the trim's orientation if necessary
384
draggedTrim.dock(areaId);
385
386             // Add the trim into the layout
387
layout.addTrim(areaId, draggedTrim, insertBefore);
388             LayoutUtil.resize(draggedTrim.getControl());
389             
390             // Remember the area that we're currently docked in
391
dockedArea = areaId;
392         }
393             
394         /* (non-Javadoc)
395          * @see org.eclipse.ui.internal.dnd.IDropTarget#getCursor()
396          */

397         public Cursor getCursor() {
398             // If the trim isn't docked then show the 'no smoking' sign
399
if (cursorAreaId == SWT.NONE) {
400                 return windowComposite.getDisplay().getSystemCursor(SWT.CURSOR_NO);
401             }
402             
403             // It's docked; show the four-way arrow cursor
404
return windowComposite.getDisplay().getSystemCursor(SWT.CURSOR_SIZEALL);
405         }
406
407         /* (non-Javadoc)
408          * @see org.eclipse.ui.internal.dnd.IDropTarget#getSnapRectangle()
409          */

410         public Rectangle getSnapRectangle() {
411             // TODO: KLUDGE!! We don't want to show -any- snap rect
412
// but Tracker won't allow that so place it where it won't be visible
413
return new Rectangle(100000, 0,0,0);
414         }
415
416         /* (non-Javadoc)
417          * @see org.eclipse.ui.internal.dnd.IDropTarget2#dragFinished(boolean)
418          */

419         public void dragFinished(boolean dropPerformed) {
420             // If we didn't perform a drop then restore the original position
421
if (!dropPerformed && dockedArea == SWT.NONE) {
422                 // Force the dragged trim back into its original position...
423
redock();
424             }
425             
426             // Set the draggedTrim to null. This indicates that we're no longer
427
// dragging the trim. The first call to the TrimDropTarget's 'drag' method
428
// will reset this the next time a drag starts.
429
draggedTrim = null;
430         }
431     }
432     
433     private ActualTrimDropTarget dropTarget;
434     
435     private TrimLayout layout;
436     private Composite windowComposite;
437
438     /**
439      * Create a new drop target capable of accepting IWindowTrim items
440      *
441      * @param someComposite The control owning the TrimLayout
442      * @param theWindow the workbenchWindow
443      */

444     public TrimDropTarget(Composite someComposite, WorkbenchWindow theWindow) {
445         layout = (TrimLayout) someComposite.getLayout();
446         windowComposite = someComposite;
447
448         // Create an instance of a drop target to use
449
dropTarget = new ActualTrimDropTarget();
450     }
451
452     /* (non-Javadoc)
453      * @see org.eclipse.ui.internal.dnd.IDragOverListener#drag(org.eclipse.swt.widgets.Control, java.lang.Object, org.eclipse.swt.graphics.Point, org.eclipse.swt.graphics.Rectangle)
454      */

455     public IDropTarget drag(Control currentControl, Object JavaDoc draggedObject,
456             Point position, final Rectangle dragRectangle) {
457         
458         // Have to be dragging trim
459
if (!(draggedObject instanceof IWindowTrim)) {
460             return null;
461         }
462         
463         // OK, we're dragging trim. is it from -this- shell?
464
IWindowTrim trim = (IWindowTrim) draggedObject;
465         if (trim.getControl().getShell() != windowComposite.getShell()) {
466             return null;
467         }
468         
469         // If this is the -first- drag then inform the drop target
470
if (dropTarget.draggedTrim == null) {
471             dropTarget.startDrag(trim);
472         }
473
474         // Forward on to the 'actual' drop target for feedback
475
dropTarget.track(position);
476         
477         // Spin the paint loop after every track
478
windowComposite.getDisplay().update();
479         
480         return dropTarget;
481     }
482 }
483
Popular Tags