1 11 12 package org.eclipse.ui.actions; 13 14 import java.util.ArrayList ; 15 import java.util.List ; 16 17 import org.eclipse.jface.action.IMenuManager; 18 import org.eclipse.jface.action.MenuManager; 19 import org.eclipse.swt.custom.StyledText; 20 import org.eclipse.swt.graphics.GC; 21 import org.eclipse.swt.graphics.Point; 22 import org.eclipse.swt.graphics.Rectangle; 23 import org.eclipse.swt.widgets.Control; 24 import org.eclipse.swt.widgets.Display; 25 import org.eclipse.swt.widgets.Menu; 26 import org.eclipse.swt.widgets.Table; 27 import org.eclipse.swt.widgets.TableItem; 28 import org.eclipse.swt.widgets.Tree; 29 import org.eclipse.swt.widgets.TreeItem; 30 31 37 public abstract class QuickMenuCreator { 38 39 private static final int CHAR_INDENT = 3; 40 41 private Menu quickMenu; 42 43 46 public void createMenu() { 47 Display display = Display.getCurrent(); 48 if (display == null) { 49 return; 50 } 51 Control focus = display.getFocusControl(); 52 if (focus == null || focus.isDisposed()) { 53 return; 54 } 55 56 MenuManager menu = new MenuManager(); 57 fillMenu(menu); 58 if (quickMenu != null) { 59 quickMenu.dispose(); 60 quickMenu = null; 61 } 62 quickMenu = menu.createContextMenu(focus.getShell()); 63 Point location = computeMenuLocation(focus); 64 if (location == null) { 65 return; 66 } 67 quickMenu.setLocation(location); 68 quickMenu.setVisible(true); 69 } 70 71 77 protected abstract void fillMenu(IMenuManager menu); 78 79 86 private Point computeMenuLocation(Control focus) { 87 Point cursorLocation = focus.getDisplay().getCursorLocation(); 88 Rectangle clientArea = null; 89 Point result = null; 90 if (focus instanceof StyledText) { 91 StyledText styledText = (StyledText) focus; 92 clientArea = styledText.getClientArea(); 93 result = computeMenuLocation(styledText); 94 } else if (focus instanceof Tree) { 95 Tree tree = (Tree) focus; 96 clientArea = tree.getClientArea(); 97 result = computeMenuLocation(tree); 98 } else if (focus instanceof Table) { 99 Table table = (Table) focus; 100 clientArea = table.getClientArea(); 101 result = computeMenuLocation(table); 102 } 103 if (result == null) { 104 result = focus.toControl(cursorLocation); 105 } 106 if (clientArea != null && !clientArea.contains(result)) { 107 result = new Point(clientArea.x + clientArea.width / 2, 108 clientArea.y + clientArea.height / 2); 109 } 110 Rectangle shellArea = focus.getShell().getClientArea(); 111 if (!shellArea.contains(focus.getShell().toControl( 112 focus.toDisplay(result)))) { 113 result = new Point(shellArea.x + shellArea.width / 2, shellArea.y 114 + shellArea.height / 2); 115 } 116 return focus.toDisplay(result); 117 } 118 119 130 private Point computeMenuLocation(StyledText text) { 131 Point result = text.getLocationAtOffset(text.getCaretOffset()); 132 result.y += text.getLineHeight(); 133 if (!text.getClientArea().contains(result)) { 134 return null; 135 } 136 return result; 137 } 138 139 149 private Point computeMenuLocation(Tree tree) { 150 TreeItem[] items = tree.getSelection(); 151 Rectangle clientArea = tree.getClientArea(); 152 switch (items.length) { 153 case 0: 154 return null; 155 case 1: 156 Rectangle bounds = items[0].getBounds(); 157 Rectangle intersect = clientArea.intersection(bounds); 158 if (intersect != null && intersect.height == bounds.height) { 159 return new Point(Math.max(0, bounds.x 160 + getAvarageCharWith(tree) * CHAR_INDENT), bounds.y 161 + bounds.height); 162 } 163 return null; 164 165 default: 166 Rectangle[] rectangles = new Rectangle[items.length]; 167 for (int i = 0; i < rectangles.length; i++) { 168 rectangles[i] = items[i].getBounds(); 169 } 170 Point cursorLocation = tree.getDisplay().getCursorLocation(); 171 Point result = findBestLocation(getIncludedPositions(rectangles, 172 clientArea), tree.toControl(cursorLocation)); 173 if (result != null) { 174 result.x = result.x + getAvarageCharWith(tree) * CHAR_INDENT; 175 } 176 return result; 177 } 178 } 179 180 190 private Point computeMenuLocation(Table table) { 191 TableItem[] items = table.getSelection(); 192 Rectangle clientArea = table.getClientArea(); 193 switch (items.length) { 194 case 0: { 195 return null; 196 } 197 case 1: { 198 Rectangle bounds = items[0].getBounds(0); 199 Rectangle iBounds = items[0].getImageBounds(0); 200 Rectangle intersect = clientArea.intersection(bounds); 201 if (intersect != null && intersect.height == bounds.height) { 202 return new Point(Math.max(0, bounds.x + iBounds.width 203 + getAvarageCharWith(table) * CHAR_INDENT), bounds.y 204 + bounds.height); 205 } 206 return null; 207 208 } 209 default: { 210 Rectangle[] rectangles = new Rectangle[items.length]; 211 for (int i = 0; i < rectangles.length; i++) { 212 rectangles[i] = items[i].getBounds(0); 213 } 214 Rectangle iBounds = items[0].getImageBounds(0); 215 Point cursorLocation = table.getDisplay().getCursorLocation(); 216 Point result = findBestLocation(getIncludedPositions(rectangles, 217 clientArea), table.toControl(cursorLocation)); 218 if (result != null) { 219 result.x = result.x + iBounds.width + getAvarageCharWith(table) 220 * CHAR_INDENT; 221 } 222 return result; 223 } 224 } 225 } 226 227 private Point[] getIncludedPositions(Rectangle[] rectangles, 228 Rectangle widgetBounds) { 229 List result = new ArrayList (); 230 for (int i = 0; i < rectangles.length; i++) { 231 Rectangle rectangle = rectangles[i]; 232 Rectangle intersect = widgetBounds.intersection(rectangle); 233 if (intersect != null && intersect.height == rectangle.height) { 234 result.add(new Point(intersect.x, intersect.y 235 + intersect.height)); 236 } 237 } 238 return (Point[]) result.toArray(new Point[result.size()]); 239 } 240 241 private Point findBestLocation(Point[] points, Point relativeCursor) { 242 Point result = null; 243 double bestDist = Double.MAX_VALUE; 244 for (int i = 0; i < points.length; i++) { 245 Point point = points[i]; 246 int a = 0; 247 int b = 0; 248 if (point.x > relativeCursor.x) { 249 a = point.x - relativeCursor.x; 250 } else { 251 a = relativeCursor.x - point.x; 252 } 253 if (point.y > relativeCursor.y) { 254 b = point.y - relativeCursor.y; 255 } else { 256 b = relativeCursor.y - point.y; 257 } 258 double dist = Math.sqrt(a * a + b * b); 259 if (dist < bestDist) { 260 result = point; 261 bestDist = dist; 262 } 263 } 264 return result; 265 } 266 267 private int getAvarageCharWith(Control control) { 268 GC gc = null; 269 try { 270 gc = new GC(control); 271 return gc.getFontMetrics().getAverageCharWidth(); 272 } finally { 273 if (gc != null) { 274 gc.dispose(); 275 } 276 } 277 } 278 279 283 public void dispose() { 284 if (quickMenu != null) { 285 quickMenu.dispose(); 286 quickMenu = null; 287 } 288 } 289 } 290 | Popular Tags |