1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.workbench.internal.contributions;
14 import org.eclipse.jface.action.Action;
15 import org.eclipse.jface.action.IMenuListener;
16 import org.eclipse.jface.action.IMenuManager;
17 import org.eclipse.jface.action.MenuManager;
18 import org.eclipse.jface.preference.IPreferenceStore;
19 import org.eclipse.jface.util.IPropertyChangeListener;
20 import org.eclipse.jface.util.PropertyChangeEvent;
21 import org.eclipse.osgi.util.NLS;
22 import org.eclipse.swt.SWT;
23 import org.eclipse.swt.graphics.Color;
24 import org.eclipse.swt.graphics.GC;
25 import org.eclipse.swt.graphics.Point;
26 import org.eclipse.swt.graphics.Rectangle;
27 import org.eclipse.swt.widgets.Composite;
28 import org.eclipse.swt.widgets.Display;
29 import org.eclipse.swt.widgets.Event;
30 import org.eclipse.swt.widgets.Listener;
31 import org.eclipse.swt.widgets.Menu;
32 import org.eclipse.ui.internal.TrimUtil;
33 import org.eclipse.ui.internal.WorkbenchMessages;
34 import org.simantics.db.MonitorContext;
35 import org.simantics.db.MonitorHandler;
36 import org.simantics.db.Session;
37 import org.simantics.db.SessionReference;
38 import org.simantics.db.SessionVariables;
39 import org.simantics.db.service.LifecycleSupport;
40 import org.simantics.db.service.SessionMonitorSupport;
43 * The graph request status control, which shows the current graph request state
44 * of a workbench window in the window trim.
46 * Adapted from Eclipse's Heap Status control.
49 public class GraphRequestStatusTrim extends Composite {
51 final String requestStatusMessage = "{0}R / {1}W";
52 final String requestToolTip = "Session: {0}\nPending: {1} read requests, {2} write requests";
54 private boolean armed;
55 //private final Image gcImage;
56 private final Color bgCol, lowMemCol, freeMemCol;
57 private Color topLeftCol;
58 private final Color bottomRightCol, sepCol, textCol;
59 //private Color armCol;
60 //private final Canvas button;
61 private final IPreferenceStore prefStore;
62 private final int updateInterval = 200;
63 private boolean hasChanged;
65 private Rectangle imgBounds = new Rectangle(0,0,12,12);
67 private SessionMonitorSupport session;
68 private MonitorContext monitorContext;
69 private long lastRedrawTime = 0;
72 SessionReference sessionRef;
83 private final Status status = new Status();
85 private final MonitorHandler monitorHandler = new MonitorHandler() {
87 public void valuesChanged(MonitorContext c) {
89 long time = System.currentTimeMillis();
90 // Require that 100ms has passed before refreshing again.
91 if ((time - 100) > lastRedrawTime) {
92 lastRedrawTime = time;
94 getDisplay().asyncExec(timer);
100 private final Runnable timer = new Runnable() {
109 getDisplay().timerExec(updateInterval, this);
114 private final IPropertyChangeListener prefListener = new IPropertyChangeListener() {
115 public void propertyChange(PropertyChangeEvent event) {
116 // if (IHeapStatusConstants.PREF_UPDATE_INTERVAL.equals(event.getProperty())) {
117 // setUpdateIntervalInMS(prefStore.getInt(IHeapStatusConstants.PREF_UPDATE_INTERVAL));
119 // else if (IHeapStatusConstants.PREF_SHOW_MAX.equals(event.getProperty())) {
120 // showMax = prefStore.getBoolean(IHeapStatusConstants.PREF_SHOW_MAX);
125 public void attachToSession(Session session) {
126 if (session != this.session) {
127 if (monitorContext != null) {
128 this.session.unregisterMonitor(monitorContext);
129 monitorContext = null;
134 SessionMonitorSupport support = null;
136 support = session.peekService(SessionMonitorSupport.class);
137 if (support == null) {
142 this.session = support;
143 monitorContext = this.session.registerMonitor(monitorHandler);
144 LifecycleSupport lifecycleSupport = session.getService(LifecycleSupport.class);
145 status.sessionRef = lifecycleSupport.getSessionReference();
146 getDisplay().asyncExec(timer);
151 * Creates a new heap status control with the given parent, and using
152 * the given preference store to obtain settings such as the refresh
155 * @param parent the parent composite
156 * @param prefStore the preference store
158 public GraphRequestStatusTrim(Composite parent, IPreferenceStore prefStore) {
159 super(parent, SWT.NONE);
161 this.prefStore = prefStore;
162 prefStore.addPropertyChangeListener(prefListener);
164 // setUpdateIntervalInMS(prefStore.getInt(IHeapStatusConstants.PREF_UPDATE_INTERVAL));
165 // showMax = prefStore.getBoolean(IHeapStatusConstants.PREF_SHOW_MAX);
167 //button = new Canvas(this, SWT.NONE);
169 // ImageDescriptor imageDesc = SimanticsUI.getImageDescriptor("icons/etool16/wrench.png"); //$NON-NLS-1$
170 // gcImage = imageDesc.createImage();
171 // if (gcImage != null) {
172 // imgBounds = gcImage.getBounds();
174 Display display = getDisplay();
175 // usedMemCol = display.getSystemColor(SWT.COLOR_INFO_BACKGROUND);
176 lowMemCol = new Color(display, 255, 70, 70); // medium red
177 freeMemCol = new Color(display, 255, 190, 125); // light orange
178 bgCol = display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
179 sepCol = topLeftCol = /*armCol =*/ display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
180 bottomRightCol = display.getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
181 textCol = display.getSystemColor(SWT.COLOR_INFO_FOREGROUND);
182 // markCol = textCol;
186 Listener listener = new Listener() {
188 public void handleEvent(Event event) {
189 switch (event.type) {
194 // Rectangle rect = getClientArea();
195 // button.setBounds(rect.width - imgBounds.width - 1, 1, imgBounds.width, rect.height - 2);
198 if (event.widget == GraphRequestStatusTrim.this) {
199 paintComposite(event.gc);
201 // else if (event.widget == button) {
202 // paintButton(event.gc);
206 if (event.button == 1) {
207 // TODO: if the DB is locked, somehow release it ?
212 if (event.button == 1) {
213 if (event.widget == GraphRequestStatusTrim.this) {
215 // } else if (event.widget == button) {
227 addListener(SWT.Dispose, listener);
228 addListener(SWT.MouseDown, listener);
229 addListener(SWT.Paint, listener);
230 addListener(SWT.Resize, listener);
231 // button.addListener(SWT.MouseDown, listener);
232 // button.addListener(SWT.MouseExit, listener);
233 // button.addListener(SWT.MouseUp, listener);
234 // button.addListener(SWT.Paint, listener);
236 // make sure stats are updated before first paint
239 getDisplay().asyncExec(new Runnable() {
242 getDisplay().timerExec(updateInterval, timer);
248 // private void setUpdateIntervalInMS(int interval) {
249 // updateInterval = Math.max(100, interval);
252 private void doDispose() {
253 prefStore.removePropertyChangeListener(prefListener);
254 // if (gcImage != null) {
255 // gcImage.dispose();
258 if (lowMemCol != null) {
261 if (freeMemCol != null) {
262 freeMemCol.dispose();
267 * @see org.eclipse.swt.widgets.Composite#computeSize(int, int, boolean)
270 public Point computeSize(int wHint, int hHint, boolean changed) {
271 GC gc = new GC(this);
272 Point p = gc.textExtent("MMMMMMM");
273 int height = imgBounds.height;
274 // choose the largest of
275 // - Text height + margins
276 // - Image height + margins
277 // - Default Trim heightin
278 height = Math.max(height, p.y) + 4;
279 height = Math.max(TrimUtil.TRIM_DEFAULT_HEIGHT, height);
281 return new Point(p.x + 2, height);
284 private void arm(boolean armed) {
285 if (this.armed == armed) {
294 * Creates the context menu
296 private void createContextMenu() {
297 MenuManager menuMgr = new MenuManager();
298 menuMgr.setRemoveAllWhenShown(true);
299 menuMgr.addMenuListener(new IMenuListener() {
300 public void menuAboutToShow(IMenuManager menuMgr) {
304 Menu menu = menuMgr.createContextMenu(this);
308 private void fillMenu(IMenuManager menuMgr) {
309 //menuMgr.add(new ShowSessionsAction());
310 menuMgr.add(new CloseAction());
313 // private void paintButton(GC gc) {
314 // Rectangle rect = button.getClientArea();
317 // gc.setBackground(armCol);
318 // gc.fillRectangle(rect.x, rect.y, rect.width, rect.height);
320 //// if (gcImage != null) {
321 //// int by = (rect.height - imgBounds.height) / 2 + rect.y; // button y
322 //// gc.drawImage(gcImage, rect.x, by);
327 private void paintComposite(GC gc) {
328 Rectangle rect = getClientArea();
333 // int bw = imgBounds.width; // button width
335 int dx = x + w - bw - 2; // divider x
336 // int sw = w - bw - 3; // status width
337 // int uw = (int) (sw * usedMem / totalMem); // used mem width
338 // int ux = x + 1 + uw; // used mem right edge
340 gc.setBackground(bgCol);
341 gc.fillRectangle(rect);
342 gc.setForeground(sepCol);
343 gc.drawLine(dx, y, dx, y + h);
344 // gc.drawLine(ux, y, ux, y + h);
345 gc.setForeground(topLeftCol);
346 gc.drawLine(x, y, x+w, y);
347 gc.drawLine(x, y, x, y+h);
348 gc.setForeground(bottomRightCol);
349 gc.drawLine(x+w-1, y, x+w-1, y+h);
350 gc.drawLine(x, y+h-1, x+w, y+h-1);
352 // gc.setBackground(usedMemCol);
353 // gc.fillRectangle(x + 1, y + 1, uw, h - 2);
355 String reads = String.valueOf(status.reads);
356 String writes = String.valueOf(status.writes);
357 String s = NLS.bind(requestStatusMessage, new String[] { reads, writes });
359 Point p = gc.textExtent(s);
360 //int sx = (rect.width - 15 - p.x) / 2 + rect.x + 1;
361 int sx = (rect.width - 2 - p.x) / 2 + rect.x + 1;
362 int sy = (rect.height - 2 - p.y) / 2 + rect.y + 1;
363 gc.setForeground(textCol);
365 gc.drawString(s, sx, sy, true);
367 // draw an I-shaped bar in the foreground colour for the mark (if present)
369 // int ssx = (int) (sw * mark / totalMem) + x + 1;
370 // paintMark(gc, ssx, y, h);
374 // private void paintMark(GC gc, int x, int y, int h) {
375 // gc.setForeground(markCol);
376 // gc.drawLine(x, y+1, x, y+h-2);
377 // gc.drawLine(x-1, y+1, x+1, y+1);
378 // gc.drawLine(x-1, y+h-2, x+1, y+h-2);
381 private void updateStats() {
382 if (monitorContext == null)
385 int reads = monitorContext.getInteger(SessionVariables.QUEUED_READS);
386 int writes = monitorContext.getInteger(SessionVariables.QUEUED_WRITES);
387 if (reads != status.reads) {
388 status.reads = reads;
389 this.hasChanged = true;
391 if (writes != status.writes) {
392 status.writes = writes;
393 this.hasChanged = true;
397 private void updateToolTip() {
399 if (status.sessionRef != null)
400 server = status.sessionRef.getServerReference().toString();
401 String reads = String.valueOf(status.reads);
402 String writes = String.valueOf(status.writes);
403 String toolTip = NLS.bind(requestToolTip, new String[] { server, reads, writes });
404 if (!toolTip.equals(getToolTipText())) {
405 setToolTipText(toolTip);
410 class ShowSessionsAction extends Action{
411 ShowSessionsAction(){
412 super("Show Local Sessions");
416 * @see org.eclipse.jface.action.IAction#run()
423 class CloseAction extends Action{
425 super(WorkbenchMessages.WorkbenchWindow_close);
429 * @see org.eclipse.jface.action.IAction#run()