1 11 12 package org.eclipse.ui.internal.navigator.resources.actions; 13 14 15 import java.util.ArrayList ; 16 import java.util.List ; 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 51 public abstract class QuickMenuAction extends Action { 52 53 private static final int CHAR_INDENT = 3; 54 55 61 public QuickMenuAction(String commandId) { 62 setActionDefinitionId(commandId); 63 } 64 65 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 103 protected abstract void fillMenu(IMenuManager menu); 104 105 111 public String getShortCutString() { 112 final ICommandManager commandManager = PlatformUI.getWorkbench().getCommandSupport().getCommandManager(); 113 final ICommand command = commandManager.getCommand(getActionDefinitionId()); 114 if (command.isDefined()) { 115 List 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 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 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 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 result = new ArrayList (); 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 |