]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.workbench/src/org/simantics/workbench/internal/contributions/GraphRequestStatusTrim.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.workbench / src / org / simantics / workbench / internal / contributions / GraphRequestStatusTrim.java
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
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.workbench.internal.contributions;\r
13 \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
41 \r
42 /**\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
45  * <p>\r
46  * Adapted from Eclipse's Heap Status control.\r
47  * </p>\r
48  */\r
49 public class GraphRequestStatusTrim extends Composite {\r
50 \r
51     final String requestStatusMessage = "{0}R / {1}W";\r
52     final String requestToolTip = "Session: {0}\nPending: {1} read requests, {2} write requests";\r
53 \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
64     // start with 12x12\r
65     private Rectangle imgBounds = new Rectangle(0,0,12,12);\r
66 \r
67     private SessionMonitorSupport session;\r
68     private MonitorContext monitorContext;\r
69     private long lastRedrawTime = 0;\r
70 \r
71     class Status {\r
72         SessionReference sessionRef;\r
73         int reads;\r
74         int writes;\r
75 \r
76         void clear() {\r
77             sessionRef = null;\r
78             reads = 0;\r
79             writes = 0;\r
80         }\r
81     }\r
82 \r
83     private final Status status = new Status();\r
84 \r
85     private final MonitorHandler monitorHandler = new MonitorHandler() {\r
86         @Override\r
87         public void valuesChanged(MonitorContext c) {\r
88             //updateStats();\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
95                 }\r
96             }\r
97         }\r
98     };\r
99 \r
100     private final Runnable timer = new Runnable() {\r
101         public void run() {\r
102             if (!isDisposed()) {\r
103                 updateStats();\r
104                 if (hasChanged) {\r
105                     updateToolTip();\r
106                     redraw();\r
107                     hasChanged = false;\r
108                 }\r
109                 getDisplay().timerExec(updateInterval, this);\r
110             }\r
111         }\r
112     };\r
113 \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
118 //          }\r
119 //          else if (IHeapStatusConstants.PREF_SHOW_MAX.equals(event.getProperty())) {\r
120 //          showMax = prefStore.getBoolean(IHeapStatusConstants.PREF_SHOW_MAX);\r
121 //          }\r
122         }\r
123     };\r
124 \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
131                 status.clear();\r
132             }\r
133 \r
134             SessionMonitorSupport support = null;\r
135             if (session != null)\r
136                 support = session.peekService(SessionMonitorSupport.class);\r
137             if (support == null) {\r
138                 hasChanged = true;\r
139                 return;\r
140             }\r
141 \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
147         }\r
148     }\r
149 \r
150     /**\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
153      * interval.\r
154      * \r
155      * @param parent the parent composite\r
156      * @param prefStore the preference store\r
157      */\r
158     public GraphRequestStatusTrim(Composite parent, IPreferenceStore prefStore) {\r
159         super(parent, SWT.NONE);\r
160 \r
161         this.prefStore = prefStore;\r
162         prefStore.addPropertyChangeListener(prefListener);\r
163 \r
164 //        setUpdateIntervalInMS(prefStore.getInt(IHeapStatusConstants.PREF_UPDATE_INTERVAL));\r
165 //        showMax = prefStore.getBoolean(IHeapStatusConstants.PREF_SHOW_MAX);\r
166 \r
167         //button = new Canvas(this, SWT.NONE);\r
168 \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
173 //        }\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
183 \r
184         createContextMenu();\r
185 \r
186         Listener listener = new Listener() {\r
187 \r
188             public void handleEvent(Event event) {\r
189                 switch (event.type) {\r
190                     case SWT.Dispose:\r
191                         doDispose();\r
192                         break;\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
196 //                        break;\r
197                     case SWT.Paint:\r
198                         if (event.widget == GraphRequestStatusTrim.this) {\r
199                             paintComposite(event.gc);\r
200                         }\r
201 //                        else if (event.widget == button) {\r
202 //                            paintButton(event.gc);\r
203 //                        }\r
204                         break;\r
205                     case SWT.MouseUp:\r
206                         if (event.button == 1) {\r
207                             // TODO: if the DB is locked, somehow release it ?\r
208                             arm(false);\r
209                         }\r
210                         break;\r
211                     case SWT.MouseDown:\r
212                         if (event.button == 1) {\r
213                             if (event.widget == GraphRequestStatusTrim.this) {\r
214 //                          setMark();\r
215 //                            } else if (event.widget == button) {\r
216 //                                arm(true);\r
217                             }\r
218                         }\r
219                         break;\r
220                     case SWT.MouseExit:\r
221                         arm(false);\r
222                         break;\r
223                 }\r
224             }\r
225 \r
226         };\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
235 \r
236         // make sure stats are updated before first paint\r
237         //updateStats();\r
238 \r
239         getDisplay().asyncExec(new Runnable() {\r
240             public void run() {\r
241                 if (!isDisposed()) {\r
242                     getDisplay().timerExec(updateInterval, timer);\r
243                 }\r
244             }\r
245         });\r
246     }\r
247 \r
248 //    private void setUpdateIntervalInMS(int interval) {\r
249 //        updateInterval = Math.max(100, interval);\r
250 //    }\r
251 \r
252     private void doDispose() {\r
253         prefStore.removePropertyChangeListener(prefListener);\r
254 //        if (gcImage != null) {\r
255 //            gcImage.dispose();\r
256 //        }\r
257 \r
258         if (lowMemCol != null) {\r
259             lowMemCol.dispose();\r
260         }\r
261         if (freeMemCol != null) {\r
262             freeMemCol.dispose();\r
263         }\r
264     }\r
265 \r
266     /* (non-Javadoc)\r
267      * @see org.eclipse.swt.widgets.Composite#computeSize(int, int, boolean)\r
268      */\r
269     @Override\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
280         gc.dispose();\r
281         return new Point(p.x + 2, height);\r
282     }\r
283 \r
284     private void arm(boolean armed) {\r
285         if (this.armed == armed) {\r
286             return;\r
287         }\r
288         this.armed = armed;\r
289 //        button.redraw();\r
290 //        button.update();\r
291     }\r
292 \r
293     /**\r
294      * Creates the context menu\r
295      */\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
301                 fillMenu(menuMgr);\r
302             }\r
303         });\r
304         Menu menu = menuMgr.createContextMenu(this);\r
305         setMenu(menu);\r
306     }\r
307 \r
308     private void fillMenu(IMenuManager menuMgr) {\r
309         //menuMgr.add(new ShowSessionsAction());\r
310         menuMgr.add(new CloseAction());\r
311     }\r
312 \r
313 //    private void paintButton(GC gc) {\r
314 //        Rectangle rect = button.getClientArea();\r
315 //\r
316 //        if (armed) {\r
317 //            gc.setBackground(armCol);\r
318 //            gc.fillRectangle(rect.x, rect.y, rect.width, rect.height);\r
319 //        }\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
323 ////        }\r
324 //    }\r
325 \r
326 \r
327     private void paintComposite(GC gc) {\r
328         Rectangle rect = getClientArea();\r
329         int x = rect.x;\r
330         int y = rect.y;\r
331         int w = rect.width;\r
332         int h = rect.height;\r
333 //        int bw = imgBounds.width; // button width\r
334         int bw = 0;\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
339 \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
351 \r
352 //        gc.setBackground(usedMemCol);\r
353 //        gc.fillRectangle(x + 1, y + 1, uw, h - 2);\r
354 \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
358 \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
364         gc.setAlpha(192);\r
365         gc.drawString(s, sx, sy, true);\r
366 \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
371 //        }\r
372     }\r
373 \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
379 //      }\r
380 \r
381     private void updateStats() {\r
382         if (monitorContext == null)\r
383             return;\r
384 \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
390         }\r
391         if (writes != status.writes) {\r
392             status.writes = writes;\r
393             this.hasChanged = true;\r
394         }\r
395     }\r
396 \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
406         }\r
407     }\r
408 \r
409 \r
410     class ShowSessionsAction extends Action{\r
411         ShowSessionsAction(){\r
412             super("Show Local Sessions");\r
413         }\r
414 \r
415         /* (non-Javadoc)\r
416          * @see org.eclipse.jface.action.IAction#run()\r
417          */\r
418         @Override\r
419         public void run(){\r
420         }\r
421     }\r
422 \r
423     class CloseAction extends Action{\r
424         CloseAction(){\r
425             super(WorkbenchMessages.WorkbenchWindow_close);\r
426         }\r
427 \r
428         /* (non-Javadoc)\r
429          * @see org.eclipse.jface.action.IAction#run()\r
430          */\r
431         @Override\r
432         public void run(){\r
433             dispose();\r
434         }\r
435     }\r
436 \r
437 }\r
438 \r