1 11 package org.eclipse.jdt.internal.ui.actions; 12 13 import java.util.ArrayList ; 14 import java.util.List ; 15 16 import org.eclipse.swt.custom.StyledText; 17 import org.eclipse.swt.graphics.GC; 18 import org.eclipse.swt.graphics.Point; 19 import org.eclipse.swt.graphics.Rectangle; 20 import org.eclipse.swt.widgets.Control; 21 import org.eclipse.swt.widgets.Display; 22 import org.eclipse.swt.widgets.Menu; 23 import org.eclipse.swt.widgets.Table; 24 import org.eclipse.swt.widgets.TableItem; 25 import org.eclipse.swt.widgets.Tree; 26 import org.eclipse.swt.widgets.TreeItem; 27 28 import org.eclipse.jface.action.Action; 29 import org.eclipse.jface.action.IMenuManager; 30 import org.eclipse.jface.action.MenuManager; 31 32 import org.eclipse.ui.PlatformUI; 33 import org.eclipse.ui.keys.IBindingService; 34 35 41 public abstract class QuickMenuAction extends Action { 42 43 private static final int CHAR_INDENT= 3; 44 45 51 public QuickMenuAction(String commandId) { 52 setActionDefinitionId(commandId); 53 } 54 55 58 public void run() { 59 Display display= Display.getCurrent(); 60 if (display == null) 61 return; 62 Control focus= display.getFocusControl(); 63 if (focus == null || focus.isDisposed()) 64 return; 65 66 MenuManager menu= new MenuManager(); 67 fillMenu(menu); 68 final Menu widget= menu.createContextMenu(focus.getShell()); 69 Point location= computeMenuLocation(focus, widget); 70 if (location == null) 71 return; 72 widget.setLocation(location); 73 widget.setVisible(true); 74 while (!widget.isDisposed() && widget.isVisible()) { 75 if (!display.readAndDispatch()) 76 display.sleep(); 77 } 78 if (!widget.isDisposed()) { 79 widget.dispose(); 80 } 81 } 82 83 88 protected abstract void fillMenu(IMenuManager menu); 89 90 97 public String addShortcut(String menuText) { 98 String shortcut= getShortcutString(); 99 if (menuText == null || shortcut == null) 100 return menuText; 101 102 return menuText + '\t' + shortcut; 103 } 104 105 111 private String getShortcutString() { 112 IBindingService bindingService= (IBindingService)PlatformUI.getWorkbench().getAdapter(IBindingService.class); 113 if (bindingService == null) 114 return null; 115 return bindingService.getBestActiveBindingFormattedFor(getActionDefinitionId()); 116 } 117 118 private Point computeMenuLocation(Control focus, Menu menu) { 119 Point cursorLocation= focus.getDisplay().getCursorLocation(); 120 Rectangle clientArea= null; 121 Point result= null; 122 if (focus instanceof StyledText) { 123 StyledText styledText= (StyledText)focus; 124 clientArea= styledText.getClientArea(); 125 result= computeMenuLocation(styledText); 126 } else if (focus instanceof Tree) { 127 Tree tree= (Tree)focus; 128 clientArea= tree.getClientArea(); 129 result= computeMenuLocation(tree); 130 } else if (focus instanceof Table) { 131 Table table= (Table)focus; 132 clientArea= table.getClientArea(); 133 result= computeMenuLocation(table); 134 } 135 if (result == null) { 136 result= focus.toControl(cursorLocation); 137 } 138 if (clientArea != null && !clientArea.contains(result)) { 139 result= new Point( 140 clientArea.x + clientArea.width / 2, 141 clientArea.y + clientArea.height / 2); 142 } 143 Rectangle shellArea= focus.getShell().getClientArea(); 144 if (!shellArea.contains(focus.getShell().toControl(focus.toDisplay(result)))) { 145 result= new Point( 146 shellArea.x + shellArea.width / 2, 147 shellArea.y + shellArea.height / 2); 148 } 149 return focus.toDisplay(result); 150 } 151 152 162 protected Point computeMenuLocation(StyledText text) { 163 int offset= text.getCaretOffset(); 164 Point result= text.getLocationAtOffset(offset); 165 result.y+= text.getLineHeight(offset); 166 if (!text.getClientArea().contains(result)) 167 return null; 168 return result; 169 } 170 171 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( 192 Math.max(0, bounds.x + getAvarageCharWith(tree) * CHAR_INDENT), 193 bounds.y + bounds.height); 194 } else { 195 return null; 196 } 197 default: 198 Rectangle[] rectangles= new Rectangle[items.length]; 199 for (int i= 0; i < rectangles.length; i++) { 200 rectangles[i]= items[i].getBounds(); 201 } 202 Point cursorLocation= tree.getDisplay().getCursorLocation(); 203 Point result= findBestLocation(getIncludedPositions(rectangles, clientArea), 204 tree.toControl(cursorLocation)); 205 if (result != null) 206 result.x= result.x + getAvarageCharWith(tree) * CHAR_INDENT; 207 return result; 208 } 209 } 210 211 221 protected Point computeMenuLocation(Table table) { 222 TableItem[] items= table.getSelection(); 223 Rectangle clientArea= table.getClientArea(); 224 switch (items.length) { 225 case 0: { 226 return null; 227 } case 1: { 228 Rectangle bounds= items[0].getBounds(0); 229 Rectangle iBounds= items[0].getImageBounds(0); 230 Rectangle intersect= clientArea.intersection(bounds); 231 if (intersect != null && intersect.height == bounds.height) { 232 return new Point( 233 Math.max(0, bounds.x + iBounds.width + getAvarageCharWith(table) * CHAR_INDENT), 234 bounds.y + bounds.height); 235 } else { 236 return null; 237 } 238 } default: { 239 Rectangle[] rectangles= new Rectangle[items.length]; 240 for (int i= 0; i < rectangles.length; i++) { 241 rectangles[i]= items[i].getBounds(0); 242 } 243 Rectangle iBounds= items[0].getImageBounds(0); 244 Point cursorLocation= table.getDisplay().getCursorLocation(); 245 Point result= findBestLocation(getIncludedPositions(rectangles, clientArea), 246 table.toControl(cursorLocation)); 247 if (result != null) 248 result.x= result.x + iBounds.width + getAvarageCharWith(table) * CHAR_INDENT; 249 return result; 250 } 251 } 252 } 253 254 private Point[] getIncludedPositions(Rectangle[] rectangles, Rectangle widgetBounds) { 255 List result= new ArrayList (); 256 for (int i= 0; i < rectangles.length; i++) { 257 Rectangle rectangle= rectangles[i]; 258 Rectangle intersect= widgetBounds.intersection(rectangle); 259 if (intersect != null && intersect.height == rectangle.height) { 260 result.add(new Point(intersect.x, intersect.y + intersect.height)); 261 } 262 } 263 return (Point[]) result.toArray(new Point[result.size()]); 264 } 265 266 private Point findBestLocation(Point[] points, Point relativeCursor) { 267 Point result= null; 268 double bestDist= Double.MAX_VALUE; 269 for (int i= 0; i < points.length; i++) { 270 Point point= points[i]; 271 int a= 0; 272 int b= 0; 273 if (point.x > relativeCursor.x) { 274 a= point.x - relativeCursor.x; 275 } else { 276 a= relativeCursor.x - point.x; 277 } 278 if (point.y > relativeCursor.y) { 279 b= point.y - relativeCursor.y; 280 } else { 281 b= relativeCursor.y - point.y; 282 } 283 double dist= Math.sqrt(a * a + b * b); 284 if (dist < bestDist) { 285 result= point; 286 bestDist= dist; 287 } 288 } 289 return result; 290 } 291 292 private int getAvarageCharWith(Control control) { 293 GC gc= null; 294 try { 295 gc= new GC(control); 296 return gc.getFontMetrics().getAverageCharWidth(); 297 } finally { 298 if (gc != null) 299 gc.dispose(); 300 } 301 } 302 } 303 | Popular Tags |