KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > HeapStatus


1 /*******************************************************************************
2  * Copyright (c) 2005, 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  * Brock Janicyak - brockj@tpg.com.au - Fix for Bug 11142
11  * [HeapStatus] Heap status is updated too frequently
12  *******************************************************************************/

13
14 package org.eclipse.ui.internal;
15
16 import java.lang.reflect.Method JavaDoc;
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 /**
43  * The Heap Status control, which shows the heap usage statistics in the window trim.
44  *
45  * @since 3.1
46  */

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     // start with 12x12
63
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 JavaDoc timer = new Runnable JavaDoc() {
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     /**
95      * Creates a new heap status control with the given parent, and using
96      * the given preference store to obtain settings such as the refresh
97      * interval.
98      *
99      * @param parent the parent composite
100      * @param prefStore the preference store
101      */

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"); //$NON-NLS-1$
118
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); // medium red
125
freeMemCol = new Color(display, 255, 190, 125); // light orange
126
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         // make sure stats are updated before first paint
184
updateStats();
185
186         getDisplay().asyncExec(new Runnable JavaDoc() {
187             public void run() {
188                 if (!isDisposed()) {
189                     getDisplay().timerExec(updateInterval, timer);
190                 }
191             }
192         });
193     }
194
195     /**
196      * Returns the maximum memory limit, or Long.MAX_VALUE if the max is not known.
197      */

198     private long getMaxMem() {
199         long max = Long.MAX_VALUE;
200         try {
201             // Must use reflect to allow compilation against JCL/Foundation
202
Method JavaDoc maxMemMethod = Runtime JavaDoc.class.getMethod("maxMemory", new Class JavaDoc[0]); //$NON-NLS-1$
203
Object JavaDoc o = maxMemMethod.invoke(Runtime.getRuntime(), new Object JavaDoc[0]);
204             if (o instanceof Long JavaDoc) {
205                 max = ((Long JavaDoc) o).longValue();
206             }
207         }
208         catch (Exception JavaDoc e) {
209             // ignore if method missing or if there are other failures trying to determine the max
210
}
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     /* (non-Javadoc)
233      * @see org.eclipse.swt.widgets.Composite#computeSize(int, int, boolean)
234      */

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         // choose the largest of
240
// - Text height + margins
241
// - Image height + margins
242
// - Default Trim heightin
243
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     /**
259      * Creates the context menu
260      */

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 // if (isKyrsoftViewAvailable()) {
279
// menuMgr.add(new ShowKyrsoftViewAction());
280
// }
281
}
282
283     /**
284      * Sets the mark to the current usedMem level.
285      */

286     private void setMark() {
287         updateStats(); // get up-to-date stats before taking the mark
288
mark = usedMem;
289         hasChanged = true;
290         redraw();
291     }
292
293     /**
294      * Clears the mark.
295      */

296     private void clearMark() {
297         mark = -1;
298         hasChanged = true;
299         redraw();
300     }
301     
302     private void gc() {
303         BusyIndicator.showWhile(getDisplay(), new Runnable JavaDoc() {
304             public void run() {
305                 Thread JavaDoc t = new Thread JavaDoc() {
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                             // loop
315
}
316                         t.join(10);
317                     } catch (InterruptedException JavaDoc 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; // button y
341
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; // button width
360
int dx = x + w - bw - 2; // divider x
361
int sw = w - bw - 3; // status width
362
int uw = (int) (sw * usedMem / totalMem); // used mem width
363
int ux = x + 1 + uw; // used mem right edge
364

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 JavaDoc 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         // draw an I-shaped bar in the foreground colour for the mark (if present)
388
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; // button width
401
int dx = x + w - bw - 2; // divider x
402
int sw = w - bw - 3; // status width
403
int uw = (int) (sw * usedMem / maxMem); // used mem width
404
int ux = x + 1 + uw; // used mem right edge
405
int tw = (int) (sw * totalMem / maxMem); // current total mem width
406
int tx = x + 1 + tw; // current total mem right edge
407

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         // paint line for low memory threshold
432
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 JavaDoc 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         // draw an I-shaped bar in the foreground colour for the mark (if present)
447
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 JavaDoc 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 JavaDoc usedStr = convertToMegString(usedMem);
479         String JavaDoc totalStr = convertToMegString(totalMem);
480         String JavaDoc maxStr = maxMemKnown ? convertToMegString(maxMem) : WorkbenchMessages.HeapStatus_maxUnknown;
481         String JavaDoc markStr = mark == -1 ? WorkbenchMessages.HeapStatus_noMark : convertToMegString(mark);
482         String JavaDoc toolTip = NLS.bind(WorkbenchMessages.HeapStatus_memoryToolTip, new Object JavaDoc[] { usedStr, totalStr, maxStr, markStr });
483         if (!toolTip.equals(getToolTipText())) {
484             setToolTipText(toolTip);
485         }
486     }
487     
488     /**
489      * Converts the given number of bytes to a printable number of megabytes (rounded up).
490      */

491     private String JavaDoc convertToMegString(long numBytes) {
492         return NLS.bind(WorkbenchMessages.HeapStatus_meg, new Long JavaDoc(convertToMeg(numBytes)));
493     }
494
495     /**
496      * Converts the given number of bytes to the corresponding number of megabytes (rounded up).
497      */

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         /* (non-Javadoc)
543          * @see org.eclipse.jface.action.IAction#run()
544          */

545         public void run(){
546             dispose();
547         }
548     }
549
550 // /**
551
// * Returns whether the Kyrsoft memory monitor view is available.
552
// *
553
// * @return <code>true</code> if available, <code>false</code> otherwise
554
// */
555
// private boolean isKyrsoftViewAvailable() {
556
// return (Platform.getBundle(IHeapStatusConstants.KYRSOFT_PLUGIN_ID) != null) && PlatformUI.getWorkbench().getViewRegistry().find(IHeapStatusConstants.KYRSOFT_VIEW_ID) != null;
557
// }
558
//
559
// class ShowKyrsoftViewAction extends Action {
560
// ShowKyrsoftViewAction() {
561
// super(WorkbenchMessages.ShowKyrsoftViewAction_text);
562
// }
563
// public void run() {
564
// if (!isKyrsoftViewAvailable()) {
565
// MessageDialog.openError(getShell(), WorkbenchMessages.HeapStatus_Error, WorkbenchMessages.ShowKyrsoftViewAction_KyrsoftNotInstalled);
566
// return;
567
// }
568
// IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
569
// IWorkbenchPage page = window == null ? null : window.getActivePage();
570
// if (page == null) {
571
// MessageDialog.openError(getShell(), WorkbenchMessages.HeapStatus_Error, WorkbenchMessages.ShowKyrsoftViewAction_OpenPerspectiveFirst);
572
// return;
573
// }
574
// try {
575
// page.showView(IHeapStatusConstants.KYRSOFT_VIEW_ID);
576
// }
577
// catch (PartInitException e) {
578
// String msg = WorkbenchMessages.ShowKyrsoftViewAction_ErrorShowingKyrsoftView;
579
// IStatus status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, msg, e);
580
// ErrorDialog.openError(getShell(), WorkbenchMessages.HeapStatus_Error, msg, status);
581
// }
582
//
583
// }
584
// }
585

586 }
587
588
Popular Tags