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