/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.workbench.internal.contributions; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Menu; import org.eclipse.ui.internal.TrimUtil; import org.eclipse.ui.internal.WorkbenchMessages; import org.simantics.db.MonitorContext; import org.simantics.db.MonitorHandler; import org.simantics.db.Session; import org.simantics.db.SessionReference; import org.simantics.db.SessionVariables; import org.simantics.db.service.LifecycleSupport; import org.simantics.db.service.SessionMonitorSupport; /** * The graph request status control, which shows the current graph request state * of a workbench window in the window trim. *

* Adapted from Eclipse's Heap Status control. *

*/ public class GraphRequestStatusTrim extends Composite { final String requestStatusMessage = "{0}R / {1}W"; final String requestToolTip = "Session: {0}\nPending: {1} read requests, {2} write requests"; private boolean armed; //private final Image gcImage; private final Color bgCol, lowMemCol, freeMemCol; private Color topLeftCol; private final Color bottomRightCol, sepCol, textCol; //private Color armCol; //private final Canvas button; private final IPreferenceStore prefStore; private final int updateInterval = 200; private boolean hasChanged; // start with 12x12 private Rectangle imgBounds = new Rectangle(0,0,12,12); private SessionMonitorSupport session; private MonitorContext monitorContext; private long lastRedrawTime = 0; class Status { SessionReference sessionRef; int reads; int writes; void clear() { sessionRef = null; reads = 0; writes = 0; } } private final Status status = new Status(); private final MonitorHandler monitorHandler = new MonitorHandler() { @Override public void valuesChanged(MonitorContext c) { //updateStats(); long time = System.currentTimeMillis(); // Require that 100ms has passed before refreshing again. if ((time - 100) > lastRedrawTime) { lastRedrawTime = time; if (!isDisposed()) { getDisplay().asyncExec(timer); } } } }; private final Runnable timer = new Runnable() { public void run() { if (!isDisposed()) { updateStats(); if (hasChanged) { updateToolTip(); redraw(); hasChanged = false; } getDisplay().timerExec(updateInterval, this); } } }; private final IPropertyChangeListener prefListener = new IPropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { // if (IHeapStatusConstants.PREF_UPDATE_INTERVAL.equals(event.getProperty())) { // setUpdateIntervalInMS(prefStore.getInt(IHeapStatusConstants.PREF_UPDATE_INTERVAL)); // } // else if (IHeapStatusConstants.PREF_SHOW_MAX.equals(event.getProperty())) { // showMax = prefStore.getBoolean(IHeapStatusConstants.PREF_SHOW_MAX); // } } }; public void attachToSession(Session session) { if (session != this.session) { if (monitorContext != null) { this.session.unregisterMonitor(monitorContext); monitorContext = null; this.session = null; status.clear(); } SessionMonitorSupport support = null; if (session != null) support = session.peekService(SessionMonitorSupport.class); if (support == null) { hasChanged = true; return; } this.session = support; monitorContext = this.session.registerMonitor(monitorHandler); LifecycleSupport lifecycleSupport = session.getService(LifecycleSupport.class); status.sessionRef = lifecycleSupport.getSessionReference(); getDisplay().asyncExec(timer); } } /** * Creates a new heap status control with the given parent, and using * the given preference store to obtain settings such as the refresh * interval. * * @param parent the parent composite * @param prefStore the preference store */ public GraphRequestStatusTrim(Composite parent, IPreferenceStore prefStore) { super(parent, SWT.NONE); this.prefStore = prefStore; prefStore.addPropertyChangeListener(prefListener); // setUpdateIntervalInMS(prefStore.getInt(IHeapStatusConstants.PREF_UPDATE_INTERVAL)); // showMax = prefStore.getBoolean(IHeapStatusConstants.PREF_SHOW_MAX); //button = new Canvas(this, SWT.NONE); // ImageDescriptor imageDesc = SimanticsUI.getImageDescriptor("icons/etool16/wrench.png"); //$NON-NLS-1$ // gcImage = imageDesc.createImage(); // if (gcImage != null) { // imgBounds = gcImage.getBounds(); // } Display display = getDisplay(); // usedMemCol = display.getSystemColor(SWT.COLOR_INFO_BACKGROUND); lowMemCol = new Color(display, 255, 70, 70); // medium red freeMemCol = new Color(display, 255, 190, 125); // light orange bgCol = display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); sepCol = topLeftCol = /*armCol =*/ display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); bottomRightCol = display.getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW); textCol = display.getSystemColor(SWT.COLOR_INFO_FOREGROUND); // markCol = textCol; createContextMenu(); Listener listener = new Listener() { public void handleEvent(Event event) { switch (event.type) { case SWT.Dispose: doDispose(); break; // case SWT.Resize: // Rectangle rect = getClientArea(); // button.setBounds(rect.width - imgBounds.width - 1, 1, imgBounds.width, rect.height - 2); // break; case SWT.Paint: if (event.widget == GraphRequestStatusTrim.this) { paintComposite(event.gc); } // else if (event.widget == button) { // paintButton(event.gc); // } break; case SWT.MouseUp: if (event.button == 1) { // TODO: if the DB is locked, somehow release it ? arm(false); } break; case SWT.MouseDown: if (event.button == 1) { if (event.widget == GraphRequestStatusTrim.this) { // setMark(); // } else if (event.widget == button) { // arm(true); } } break; case SWT.MouseExit: arm(false); break; } } }; addListener(SWT.Dispose, listener); addListener(SWT.MouseDown, listener); addListener(SWT.Paint, listener); addListener(SWT.Resize, listener); // button.addListener(SWT.MouseDown, listener); // button.addListener(SWT.MouseExit, listener); // button.addListener(SWT.MouseUp, listener); // button.addListener(SWT.Paint, listener); // make sure stats are updated before first paint //updateStats(); getDisplay().asyncExec(new Runnable() { public void run() { if (!isDisposed()) { getDisplay().timerExec(updateInterval, timer); } } }); } // private void setUpdateIntervalInMS(int interval) { // updateInterval = Math.max(100, interval); // } private void doDispose() { prefStore.removePropertyChangeListener(prefListener); // if (gcImage != null) { // gcImage.dispose(); // } if (lowMemCol != null) { lowMemCol.dispose(); } if (freeMemCol != null) { freeMemCol.dispose(); } } /* (non-Javadoc) * @see org.eclipse.swt.widgets.Composite#computeSize(int, int, boolean) */ @Override public Point computeSize(int wHint, int hHint, boolean changed) { GC gc = new GC(this); Point p = gc.textExtent("MMMMMMM"); int height = imgBounds.height; // choose the largest of // - Text height + margins // - Image height + margins // - Default Trim heightin height = Math.max(height, p.y) + 4; height = Math.max(TrimUtil.TRIM_DEFAULT_HEIGHT, height); gc.dispose(); return new Point(p.x + 2, height); } private void arm(boolean armed) { if (this.armed == armed) { return; } this.armed = armed; // button.redraw(); // button.update(); } /** * Creates the context menu */ private void createContextMenu() { MenuManager menuMgr = new MenuManager(); menuMgr.setRemoveAllWhenShown(true); menuMgr.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager menuMgr) { fillMenu(menuMgr); } }); Menu menu = menuMgr.createContextMenu(this); setMenu(menu); } private void fillMenu(IMenuManager menuMgr) { //menuMgr.add(new ShowSessionsAction()); menuMgr.add(new CloseAction()); } // private void paintButton(GC gc) { // Rectangle rect = button.getClientArea(); // // if (armed) { // gc.setBackground(armCol); // gc.fillRectangle(rect.x, rect.y, rect.width, rect.height); // } //// if (gcImage != null) { //// int by = (rect.height - imgBounds.height) / 2 + rect.y; // button y //// gc.drawImage(gcImage, rect.x, by); //// } // } private void paintComposite(GC gc) { Rectangle rect = getClientArea(); int x = rect.x; int y = rect.y; int w = rect.width; int h = rect.height; // int bw = imgBounds.width; // button width int bw = 0; int dx = x + w - bw - 2; // divider x // int sw = w - bw - 3; // status width // int uw = (int) (sw * usedMem / totalMem); // used mem width // int ux = x + 1 + uw; // used mem right edge gc.setBackground(bgCol); gc.fillRectangle(rect); gc.setForeground(sepCol); gc.drawLine(dx, y, dx, y + h); // gc.drawLine(ux, y, ux, y + h); gc.setForeground(topLeftCol); gc.drawLine(x, y, x+w, y); gc.drawLine(x, y, x, y+h); gc.setForeground(bottomRightCol); gc.drawLine(x+w-1, y, x+w-1, y+h); gc.drawLine(x, y+h-1, x+w, y+h-1); // gc.setBackground(usedMemCol); // gc.fillRectangle(x + 1, y + 1, uw, h - 2); String reads = String.valueOf(status.reads); String writes = String.valueOf(status.writes); String s = NLS.bind(requestStatusMessage, new String[] { reads, writes }); Point p = gc.textExtent(s); //int sx = (rect.width - 15 - p.x) / 2 + rect.x + 1; int sx = (rect.width - 2 - p.x) / 2 + rect.x + 1; int sy = (rect.height - 2 - p.y) / 2 + rect.y + 1; gc.setForeground(textCol); gc.setAlpha(192); gc.drawString(s, sx, sy, true); // draw an I-shaped bar in the foreground colour for the mark (if present) // if (mark != -1) { // int ssx = (int) (sw * mark / totalMem) + x + 1; // paintMark(gc, ssx, y, h); // } } // private void paintMark(GC gc, int x, int y, int h) { // gc.setForeground(markCol); // gc.drawLine(x, y+1, x, y+h-2); // gc.drawLine(x-1, y+1, x+1, y+1); // gc.drawLine(x-1, y+h-2, x+1, y+h-2); // } private void updateStats() { if (monitorContext == null) return; int reads = monitorContext.getInteger(SessionVariables.QUEUED_READS); int writes = monitorContext.getInteger(SessionVariables.QUEUED_WRITES); if (reads != status.reads) { status.reads = reads; this.hasChanged = true; } if (writes != status.writes) { status.writes = writes; this.hasChanged = true; } } private void updateToolTip() { String server = ""; if (status.sessionRef != null) server = status.sessionRef.getServerReference().toString(); String reads = String.valueOf(status.reads); String writes = String.valueOf(status.writes); String toolTip = NLS.bind(requestToolTip, new String[] { server, reads, writes }); if (!toolTip.equals(getToolTipText())) { setToolTipText(toolTip); } } class ShowSessionsAction extends Action{ ShowSessionsAction(){ super("Show Local Sessions"); } /* (non-Javadoc) * @see org.eclipse.jface.action.IAction#run() */ @Override public void run(){ } } class CloseAction extends Action{ CloseAction(){ super(WorkbenchMessages.WorkbenchWindow_close); } /* (non-Javadoc) * @see org.eclipse.jface.action.IAction#run() */ @Override public void run(){ dispose(); } } }