KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > navigator > resources > actions > QuickMenuAction


1 /*******************************************************************************
2  * Copyright (c) 2003, 2006 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  
12 package org.eclipse.ui.internal.navigator.resources.actions;
13
14
15 import java.util.ArrayList JavaDoc;
16 import java.util.List JavaDoc;
17
18 import org.eclipse.jface.action.Action;
19 import org.eclipse.jface.action.IMenuManager;
20 import org.eclipse.jface.action.MenuManager;
21 import org.eclipse.swt.custom.StyledText;
22 import org.eclipse.swt.graphics.GC;
23 import org.eclipse.swt.graphics.Point;
24 import org.eclipse.swt.graphics.Rectangle;
25 import org.eclipse.swt.widgets.Control;
26 import org.eclipse.swt.widgets.Display;
27 import org.eclipse.swt.widgets.Menu;
28 import org.eclipse.swt.widgets.Table;
29 import org.eclipse.swt.widgets.TableItem;
30 import org.eclipse.swt.widgets.Tree;
31 import org.eclipse.swt.widgets.TreeItem;
32 import org.eclipse.ui.PlatformUI;
33 import org.eclipse.ui.commands.ICommand;
34 import org.eclipse.ui.commands.ICommandManager;
35 import org.eclipse.ui.commands.IKeySequenceBinding;
36
37 /**
38  * A quick menu actions provides support to assign short cuts to sub menus.
39  *
40  * Derived from the class of the same name in the JDT internals.
41  *
42  *
43  * <p>
44  * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
45  * part of a work in progress. There is a guarantee neither that this API will
46  * work nor that it will remain the same. Please do not use this API without
47  * consulting with the Platform/UI team.
48  * </p>
49  * @since 3.2
50  */

51 public abstract class QuickMenuAction extends Action {
52
53     private static final int CHAR_INDENT = 3;
54
55     /**
56      * Creates a new quick menu action with the given command id.
57      *
58      * @param commandId
59      * the command id of the short cut used to open the sub menu
60      */

61     public QuickMenuAction(String JavaDoc commandId) {
62         setActionDefinitionId(commandId);
63     }
64
65     /**
66      * {@inheritDoc}
67      */

68     public void run() {
69         Display display = Display.getCurrent();
70         if (display == null) {
71             return;
72         }
73         Control focus = display.getFocusControl();
74         if (focus == null || focus.isDisposed()) {
75             return;
76         }
77
78         MenuManager menu = new MenuManager();
79         fillMenu(menu);
80         final Menu widget = menu.createContextMenu(focus.getShell());
81         Point location = computeMenuLocation(focus, widget);
82         if (location == null) {
83             return;
84         }
85         widget.setLocation(location);
86         widget.setVisible(true);
87         while (!widget.isDisposed() && widget.isVisible()) {
88             if (!display.readAndDispatch()) {
89                 display.sleep();
90             }
91         }
92         if (!widget.isDisposed()) {
93             widget.dispose();
94         }
95     }
96
97     /**
98      * Hook to fill a menu manager with the items of the sub menu.
99      *
100      * @param menu
101      * the sub menu to fill
102      */

103     protected abstract void fillMenu(IMenuManager menu);
104
105     /**
106      * Returns the short cut assigned to the sub menu or <code>null</code> if no short cut is
107      * assigned.
108      *
109      * @return the short cut as a human readable string or <code>null</code>
110      */

111     public String JavaDoc getShortCutString() {
112         final ICommandManager commandManager = PlatformUI.getWorkbench().getCommandSupport().getCommandManager();
113         final ICommand command = commandManager.getCommand(getActionDefinitionId());
114         if (command.isDefined()) {
115             List JavaDoc l = command.getKeySequenceBindings();
116             if (!l.isEmpty()) {
117                 IKeySequenceBinding binding = (IKeySequenceBinding) l.get(0);
118                 return binding.getKeySequence().format();
119             }
120         }
121         return null;
122     }
123
124     private Point computeMenuLocation(Control focus, Menu menu) {
125         Point cursorLocation = focus.getDisplay().getCursorLocation();
126         Rectangle clientArea = null;
127         Point result = null;
128         if (focus instanceof StyledText) {
129             StyledText styledText = (StyledText) focus;
130             clientArea = styledText.getClientArea();
131             result = computeMenuLocation(styledText);
132         } else if (focus instanceof Tree) {
133             Tree tree = (Tree) focus;
134             clientArea = tree.getClientArea();
135             result = computeMenuLocation(tree);
136         } else if (focus instanceof Table) {
137             Table table = (Table) focus;
138             clientArea = table.getClientArea();
139             result = computeMenuLocation(table);
140         }
141         if (result == null) {
142             result = focus.toControl(cursorLocation);
143         }
144         if (clientArea != null && !clientArea.contains(result)) {
145             result = new Point(clientArea.x + clientArea.width / 2, clientArea.y + clientArea.height / 2);
146         }
147         Rectangle shellArea = focus.getShell().getClientArea();
148         if (!shellArea.contains(focus.getShell().toControl(focus.toDisplay(result)))) {
149             result = new Point(shellArea.x + shellArea.width / 2, shellArea.y + shellArea.height / 2);
150         }
151         return focus.toDisplay(result);
152     }
153
154     /**
155      * Hook to compute the menu location if the focus widget is a styled text widget.
156      *
157      * @param text
158      * the styled text widget that has the focus
159      *
160      * @return a widget relative position of the menu to pop up or <code>null</code> if now
161      * position inside the widget can be computed
162      */

163     protected Point computeMenuLocation(StyledText text) {
164         Point result = text.getLocationAtOffset(text.getCaretOffset());
165         result.y += text.getLineHeight();
166         if (!text.getClientArea().contains(result)) {
167             return null;
168         }
169         return result;
170     }
171
172     /**
173      * Hook to compute the menu location if the focus widget is a tree widget.
174      *
175      * @param tree
176      * the tree widget that has the focus
177      *
178      * @return a widget relative position of the menu to pop up or <code>null</code> if now
179      * position inside the widget can be computed
180      */

181     protected Point computeMenuLocation(Tree tree) {
182         TreeItem[] items = tree.getSelection();
183         Rectangle clientArea = tree.getClientArea();
184         switch (items.length) {
185             case 0 :
186                 return null;
187             case 1 :
188                 Rectangle bounds = items[0].getBounds();
189                 Rectangle intersect = clientArea.intersection(bounds);
190                 if (intersect != null && intersect.height == bounds.height) {
191                     return new Point(Math.max(0, bounds.x + getAvarageCharWith(tree) * CHAR_INDENT), bounds.y + bounds.height);
192                 }
193                 return null;
194
195             default :
196                 Rectangle[] rectangles = new Rectangle[items.length];
197                 for (int i = 0; i < rectangles.length; i++) {
198                     rectangles[i] = items[i].getBounds();
199                 }
200                 Point cursorLocation = tree.getDisplay().getCursorLocation();
201                 Point result = findBestLocation(getIncludedPositions(rectangles, clientArea), tree.toControl(cursorLocation));
202                 if (result != null) {
203                     result.x = result.x + getAvarageCharWith(tree) * CHAR_INDENT;
204                 }
205                 return result;
206         }
207     }
208
209     /**
210      * Hook to compute the menu location if the focus widget is a table widget.
211      *
212      * @param table
213      * the table widget that has the focus
214      *
215      * @return a widget relative position of the menu to pop up or <code>null</code> if now
216      * position inside the widget can be computed
217      */

218     protected Point computeMenuLocation(Table table) {
219         TableItem[] items = table.getSelection();
220         Rectangle clientArea = table.getClientArea();
221         switch (items.length) {
222             case 0 : {
223                 return null;
224             }
225             case 1 : {
226                 Rectangle bounds = items[0].getBounds(0);
227                 Rectangle iBounds = items[0].getImageBounds(0);
228                 Rectangle intersect = clientArea.intersection(bounds);
229                 if (intersect != null && intersect.height == bounds.height) {
230                     return new Point(Math.max(0, bounds.x + iBounds.width + getAvarageCharWith(table) * CHAR_INDENT), bounds.y + bounds.height);
231                 }
232                 return null;
233
234             }
235             default : {
236                 Rectangle[] rectangles = new Rectangle[items.length];
237                 for (int i = 0; i < rectangles.length; i++) {
238                     rectangles[i] = items[i].getBounds(0);
239                 }
240                 Rectangle iBounds = items[0].getImageBounds(0);
241                 Point cursorLocation = table.getDisplay().getCursorLocation();
242                 Point result = findBestLocation(getIncludedPositions(rectangles, clientArea), table.toControl(cursorLocation));
243                 if (result != null) {
244                     result.x = result.x + iBounds.width + getAvarageCharWith(table) * CHAR_INDENT;
245                 }
246                 return result;
247             }
248         }
249     }
250
251     private Point[] getIncludedPositions(Rectangle[] rectangles, Rectangle widgetBounds) {
252         List JavaDoc result = new ArrayList JavaDoc();
253         for (int i = 0; i < rectangles.length; i++) {
254             Rectangle rectangle = rectangles[i];
255             Rectangle intersect = widgetBounds.intersection(rectangle);
256             if (intersect != null && intersect.height == rectangle.height) {
257                 result.add(new Point(intersect.x, intersect.y + intersect.height));
258             }
259         }
260         return (Point[]) result.toArray(new Point[result.size()]);
261     }
262
263     private Point findBestLocation(Point[] points, Point relativeCursor) {
264         Point result = null;
265         double bestDist = Double.MAX_VALUE;
266         for (int i = 0; i < points.length; i++) {
267             Point point = points[i];
268             int a = 0;
269             int b = 0;
270             if (point.x > relativeCursor.x) {
271                 a = point.x - relativeCursor.x;
272             } else {
273                 a = relativeCursor.x - point.x;
274             }
275             if (point.y > relativeCursor.y) {
276                 b = point.y - relativeCursor.y;
277             } else {
278                 b = relativeCursor.y - point.y;
279             }
280             double dist = Math.sqrt(a * a + b * b);
281             if (dist < bestDist) {
282                 result = point;
283                 bestDist = dist;
284             }
285         }
286         return result;
287     }
288
289     private int getAvarageCharWith(Control control) {
290         GC gc = null;
291         try {
292             gc = new GC(control);
293             return gc.getFontMetrics().getAverageCharWidth();
294         } finally {
295             if (gc != null) {
296                 gc.dispose();
297             }
298         }
299     }
300 }
301
Popular Tags