1 13 14 package org.eclipse.ui.internal; 15 16 import java.lang.reflect.Method ; 17 18 import org.eclipse.jface.action.Action; 19 import org.eclipse.jface.action.IAction; 20 import org.eclipse.jface.action.IMenuListener; 21 import org.eclipse.jface.action.IMenuManager; 22 import org.eclipse.jface.action.MenuManager; 23 import org.eclipse.jface.preference.IPreferenceStore; 24 import org.eclipse.jface.resource.ImageDescriptor; 25 import org.eclipse.jface.util.IPropertyChangeListener; 26 import org.eclipse.jface.util.PropertyChangeEvent; 27 import org.eclipse.osgi.util.NLS; 28 import org.eclipse.swt.SWT; 29 import org.eclipse.swt.custom.BusyIndicator; 30 import org.eclipse.swt.graphics.Color; 31 import org.eclipse.swt.graphics.GC; 32 import org.eclipse.swt.graphics.Image; 33 import org.eclipse.swt.graphics.Point; 34 import org.eclipse.swt.graphics.Rectangle; 35 import org.eclipse.swt.widgets.Canvas; 36 import org.eclipse.swt.widgets.Composite; 37 import org.eclipse.swt.widgets.Display; 38 import org.eclipse.swt.widgets.Event; 39 import org.eclipse.swt.widgets.Listener; 40 import org.eclipse.swt.widgets.Menu; 41 42 47 public class HeapStatus extends Composite { 48 49 private boolean armed; 50 private Image gcImage; 51 private Color bgCol, usedMemCol, lowMemCol, freeMemCol, topLeftCol, bottomRightCol, sepCol, textCol, markCol, armCol; 52 private Canvas button; 53 private IPreferenceStore prefStore; 54 private int updateInterval; 55 private boolean showMax; 56 private long totalMem; 57 private long prevTotalMem = -1L; 58 private long prevUsedMem = -1L; 59 private boolean hasChanged; 60 private long usedMem; 61 private long mark = -1; 62 private Rectangle imgBounds = new Rectangle(0,0,12,12); 64 private long maxMem = Long.MAX_VALUE; 65 private boolean maxMemKnown; 66 private float lowMemThreshold = 0.05f; 67 private boolean showLowMemThreshold = true; 68 69 private final Runnable timer = new Runnable () { 70 public void run() { 71 if (!isDisposed()) { 72 updateStats(); 73 if (hasChanged) { 74 updateToolTip(); 75 redraw(); 76 hasChanged = false; 77 } 78 getDisplay().timerExec(updateInterval, this); 79 } 80 } 81 }; 82 83 private final IPropertyChangeListener prefListener = new IPropertyChangeListener() { 84 public void propertyChange(PropertyChangeEvent event) { 85 if (IHeapStatusConstants.PREF_UPDATE_INTERVAL.equals(event.getProperty())) { 86 setUpdateIntervalInMS(prefStore.getInt(IHeapStatusConstants.PREF_UPDATE_INTERVAL)); 87 } 88 else if (IHeapStatusConstants.PREF_SHOW_MAX.equals(event.getProperty())) { 89 showMax = prefStore.getBoolean(IHeapStatusConstants.PREF_SHOW_MAX); 90 } 91 } 92 }; 93 94 102 public HeapStatus(Composite parent, IPreferenceStore prefStore) { 103 super(parent, SWT.NONE); 104 105 maxMem = getMaxMem(); 106 maxMemKnown = maxMem != Long.MAX_VALUE; 107 108 this.prefStore = prefStore; 109 prefStore.addPropertyChangeListener(prefListener); 110 111 setUpdateIntervalInMS(prefStore.getInt(IHeapStatusConstants.PREF_UPDATE_INTERVAL)); 112 showMax = prefStore.getBoolean(IHeapStatusConstants.PREF_SHOW_MAX); 113 114 button = new Canvas(this, SWT.NONE); 115 button.setToolTipText(WorkbenchMessages.HeapStatus_buttonToolTip); 116 117 ImageDescriptor imageDesc = WorkbenchImages.getWorkbenchImageDescriptor("elcl16/trash.gif"); gcImage = imageDesc.createImage(); 119 if (gcImage != null) { 120 imgBounds = gcImage.getBounds(); 121 } 122 Display display = getDisplay(); 123 usedMemCol = display.getSystemColor(SWT.COLOR_INFO_BACKGROUND); 124 lowMemCol = new Color(display, 255, 70, 70); freeMemCol = new Color(display, 255, 190, 125); bgCol = display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); 127 sepCol = topLeftCol = armCol = display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); 128 bottomRightCol = display.getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW); 129 markCol = textCol = display.getSystemColor(SWT.COLOR_INFO_FOREGROUND); 130 131 createContextMenu(); 132 133 Listener listener = new Listener() { 134 135 public void handleEvent(Event event) { 136 switch (event.type) { 137 case SWT.Dispose: 138 doDispose(); 139 break; 140 case SWT.Resize: 141 Rectangle rect = getClientArea(); 142 button.setBounds(rect.width - imgBounds.width - 1, 1, imgBounds.width, rect.height - 2); 143 break; 144 case SWT.Paint: 145 if (event.widget == HeapStatus.this) { 146 paintComposite(event.gc); 147 } 148 else if (event.widget == button) { 149 paintButton(event.gc); 150 } 151 break; 152 case SWT.MouseUp: 153 if (event.button == 1) { 154 gc(); 155 arm(false); 156 } 157 break; 158 case SWT.MouseDown: 159 if (event.button == 1) { 160 if (event.widget == HeapStatus.this) { 161 setMark(); 162 } else if (event.widget == button) { 163 arm(true); 164 } 165 } 166 break; 167 case SWT.MouseExit: 168 arm(false); 169 break; 170 } 171 } 172 173 }; 174 addListener(SWT.Dispose, listener); 175 addListener(SWT.MouseDown, listener); 176 addListener(SWT.Paint, listener); 177 addListener(SWT.Resize, listener); 178 button.addListener(SWT.MouseDown, listener); 179 button.addListener(SWT.MouseExit, listener); 180 button.addListener(SWT.MouseUp, listener); 181 button.addListener(SWT.Paint, listener); 182 183 updateStats(); 185 186 getDisplay().asyncExec(new Runnable () { 187 public void run() { 188 if (!isDisposed()) { 189 getDisplay().timerExec(updateInterval, timer); 190 } 191 } 192 }); 193 } 194 195 198 private long getMaxMem() { 199 long max = Long.MAX_VALUE; 200 try { 201 Method maxMemMethod = Runtime .class.getMethod("maxMemory", new Class [0]); Object o = maxMemMethod.invoke(Runtime.getRuntime(), new Object [0]); 204 if (o instanceof Long ) { 205 max = ((Long ) o).longValue(); 206 } 207 } 208 catch (Exception e) { 209 } 211 return max; 212 } 213 214 private void setUpdateIntervalInMS(int interval) { 215 updateInterval = Math.max(100, interval); 216 } 217 218 private void doDispose() { 219 prefStore.removePropertyChangeListener(prefListener); 220 if (gcImage != null) { 221 gcImage.dispose(); 222 } 223 224 if (lowMemCol != null) { 225 lowMemCol.dispose(); 226 } 227 if (freeMemCol != null) { 228 freeMemCol.dispose(); 229 } 230 } 231 232 235 public Point computeSize(int wHint, int hHint, boolean changed) { 236 GC gc = new GC(this); 237 Point p = gc.textExtent(WorkbenchMessages.HeapStatus_widthStr); 238 int height = imgBounds.height; 239 height = Math.max(height, p.y) + 4; 244 height = Math.max(TrimUtil.TRIM_DEFAULT_HEIGHT, height); 245 gc.dispose(); 246 return new Point(p.x + 15, height); 247 } 248 249 private void arm(boolean armed) { 250 if (this.armed == armed) { 251 return; 252 } 253 this.armed = armed; 254 button.redraw(); 255 button.update(); 256 } 257 258 261 private void createContextMenu() { 262 MenuManager menuMgr = new MenuManager(); 263 menuMgr.setRemoveAllWhenShown(true); 264 menuMgr.addMenuListener(new IMenuListener() { 265 public void menuAboutToShow(IMenuManager menuMgr) { 266 fillMenu(menuMgr); 267 } 268 }); 269 Menu menu = menuMgr.createContextMenu(this); 270 setMenu(menu); 271 } 272 273 private void fillMenu(IMenuManager menuMgr) { 274 menuMgr.add(new SetMarkAction()); 275 menuMgr.add(new ClearMarkAction()); 276 menuMgr.add(new ShowMaxAction()); 277 menuMgr.add(new CloseHeapStatusAction()); 278 } 282 283 286 private void setMark() { 287 updateStats(); mark = usedMem; 289 hasChanged = true; 290 redraw(); 291 } 292 293 296 private void clearMark() { 297 mark = -1; 298 hasChanged = true; 299 redraw(); 300 } 301 302 private void gc() { 303 BusyIndicator.showWhile(getDisplay(), new Runnable () { 304 public void run() { 305 Thread t = new Thread () { 306 public void run() { 307 busyGC(); 308 }}; 309 t.start(); 310 while(t.isAlive()) { 311 try { 312 Display d = getDisplay(); 313 while(d != null && !d.isDisposed() && d.readAndDispatch()) { 314 } 316 t.join(10); 317 } catch (InterruptedException e) { 318 Thread.currentThread().interrupt(); 319 } 320 } 321 } 322 }); 323 } 324 325 private void busyGC() { 326 for (int i = 0; i < 2; ++i) { 327 System.gc(); 328 System.runFinalization(); 329 } 330 } 331 332 private void paintButton(GC gc) { 333 Rectangle rect = button.getClientArea(); 334 335 if (armed) { 336 gc.setBackground(armCol); 337 gc.fillRectangle(rect.x, rect.y, rect.width, rect.height); 338 } 339 if (gcImage != null) { 340 int by = (rect.height - imgBounds.height) / 2 + rect.y; gc.drawImage(gcImage, rect.x, by); 342 } 343 } 344 345 private void paintComposite(GC gc) { 346 if (showMax && maxMemKnown) { 347 paintCompositeMaxKnown(gc); 348 } else { 349 paintCompositeMaxUnknown(gc); 350 } 351 } 352 353 private void paintCompositeMaxUnknown(GC gc) { 354 Rectangle rect = getClientArea(); 355 int x = rect.x; 356 int y = rect.y; 357 int w = rect.width; 358 int h = rect.height; 359 int bw = imgBounds.width; int dx = x + w - bw - 2; int sw = w - bw - 3; int uw = (int) (sw * usedMem / totalMem); int ux = x + 1 + uw; 365 gc.setBackground(bgCol); 366 gc.fillRectangle(rect); 367 gc.setForeground(sepCol); 368 gc.drawLine(dx, y, dx, y + h); 369 gc.drawLine(ux, y, ux, y + h); 370 gc.setForeground(topLeftCol); 371 gc.drawLine(x, y, x+w, y); 372 gc.drawLine(x, y, x, y+h); 373 gc.setForeground(bottomRightCol); 374 gc.drawLine(x+w-1, y, x+w-1, y+h); 375 gc.drawLine(x, y+h-1, x+w, y+h-1); 376 377 gc.setBackground(usedMemCol); 378 gc.fillRectangle(x + 1, y + 1, uw, h - 2); 379 380 String s = NLS.bind(WorkbenchMessages.HeapStatus_status, convertToMegString(usedMem), convertToMegString(totalMem)); 381 Point p = gc.textExtent(s); 382 int sx = (rect.width - 15 - p.x) / 2 + rect.x + 1; 383 int sy = (rect.height - 2 - p.y) / 2 + rect.y + 1; 384 gc.setForeground(textCol); 385 gc.drawString(s, sx, sy, true); 386 387 if (mark != -1) { 389 int ssx = (int) (sw * mark / totalMem) + x + 1; 390 paintMark(gc, ssx, y, h); 391 } 392 } 393 394 private void paintCompositeMaxKnown(GC gc) { 395 Rectangle rect = getClientArea(); 396 int x = rect.x; 397 int y = rect.y; 398 int w = rect.width; 399 int h = rect.height; 400 int bw = imgBounds.width; int dx = x + w - bw - 2; int sw = w - bw - 3; int uw = (int) (sw * usedMem / maxMem); int ux = x + 1 + uw; int tw = (int) (sw * totalMem / maxMem); int tx = x + 1 + tw; 408 gc.setBackground(bgCol); 409 gc.fillRectangle(rect); 410 gc.setForeground(sepCol); 411 gc.drawLine(dx, y, dx, y + h); 412 gc.drawLine(ux, y, ux, y + h); 413 gc.drawLine(tx, y, tx, y + h); 414 gc.setForeground(topLeftCol); 415 gc.drawLine(x, y, x+w, y); 416 gc.drawLine(x, y, x, y+h); 417 gc.setForeground(bottomRightCol); 418 gc.drawLine(x+w-1, y, x+w-1, y+h); 419 gc.drawLine(x, y+h-1, x+w, y+h-1); 420 421 if (lowMemThreshold != 0 && ((double)(maxMem - usedMem) / (double)maxMem < lowMemThreshold)) { 422 gc.setBackground(lowMemCol); 423 } else { 424 gc.setBackground(usedMemCol); 425 } 426 gc.fillRectangle(x + 1, y + 1, uw, h - 2); 427 428 gc.setBackground(freeMemCol); 429 gc.fillRectangle(ux + 1, y + 1, tx - (ux + 1), h - 2); 430 431 if (showLowMemThreshold && lowMemThreshold != 0) { 433 gc.setForeground(lowMemCol); 434 int thresholdX = x + 1 + (int) (sw * (1.0 - lowMemThreshold)); 435 gc.drawLine(thresholdX, y + 1, thresholdX, y + h - 2); 436 } 437 438 String s = NLS.bind(WorkbenchMessages.HeapStatus_status, 439 convertToMegString(usedMem), convertToMegString(totalMem)); 440 Point p = gc.textExtent(s); 441 int sx = (rect.width - 15 - p.x) / 2 + rect.x + 1; 442 int sy = (rect.height - 2 - p.y) / 2 + rect.y + 1; 443 gc.setForeground(textCol); 444 gc.drawString(s, sx, sy, true); 445 446 if (mark != -1) { 448 int ssx = (int) (sw * mark / maxMem) + x + 1; 449 paintMark(gc, ssx, y, h); 450 } 451 } 452 453 private void paintMark(GC gc, int x, int y, int h) { 454 gc.setForeground(markCol); 455 gc.drawLine(x, y+1, x, y+h-2); 456 gc.drawLine(x-1, y+1, x+1, y+1); 457 gc.drawLine(x-1, y+h-2, x+1, y+h-2); 458 } 459 460 private void updateStats() { 461 Runtime runtime = Runtime.getRuntime(); 462 totalMem = runtime.totalMemory(); 463 long freeMem = runtime.freeMemory(); 464 usedMem = totalMem - freeMem; 465 466 if (convertToMeg(prevUsedMem) != convertToMeg(usedMem)) { 467 prevUsedMem = usedMem; 468 this.hasChanged = true; 469 } 470 471 if (prevTotalMem != totalMem) { 472 prevTotalMem = totalMem; 473 this.hasChanged = true; 474 } 475 } 476 477 private void updateToolTip() { 478 String usedStr = convertToMegString(usedMem); 479 String totalStr = convertToMegString(totalMem); 480 String maxStr = maxMemKnown ? convertToMegString(maxMem) : WorkbenchMessages.HeapStatus_maxUnknown; 481 String markStr = mark == -1 ? WorkbenchMessages.HeapStatus_noMark : convertToMegString(mark); 482 String toolTip = NLS.bind(WorkbenchMessages.HeapStatus_memoryToolTip, new Object [] { usedStr, totalStr, maxStr, markStr }); 483 if (!toolTip.equals(getToolTipText())) { 484 setToolTipText(toolTip); 485 } 486 } 487 488 491 private String convertToMegString(long numBytes) { 492 return NLS.bind(WorkbenchMessages.HeapStatus_meg, new Long (convertToMeg(numBytes))); 493 } 494 495 498 private long convertToMeg(long numBytes) { 499 return (numBytes + (512 * 1024)) / (1024 * 1024); 500 } 501 502 503 class SetMarkAction extends Action { 504 SetMarkAction() { 505 super(WorkbenchMessages.SetMarkAction_text); 506 } 507 508 public void run() { 509 setMark(); 510 } 511 } 512 513 class ClearMarkAction extends Action { 514 ClearMarkAction() { 515 super(WorkbenchMessages.ClearMarkAction_text); 516 } 517 518 public void run() { 519 clearMark(); 520 } 521 } 522 523 class ShowMaxAction extends Action { 524 ShowMaxAction() { 525 super(WorkbenchMessages.ShowMaxAction_text, IAction.AS_CHECK_BOX); 526 setEnabled(maxMemKnown); 527 setChecked(showMax); 528 } 529 530 public void run() { 531 prefStore.setValue(IHeapStatusConstants.PREF_SHOW_MAX, isChecked()); 532 redraw(); 533 } 534 } 535 536 class CloseHeapStatusAction extends Action{ 537 538 CloseHeapStatusAction(){ 539 super(WorkbenchMessages.WorkbenchWindow_close ); 540 } 541 542 545 public void run(){ 546 dispose(); 547 } 548 } 549 550 586 } 587 588 | Popular Tags |