]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.simulation.ui/src/org/simantics/simulation/ui/handlers/TimerContribution.java
e3734876297cfc2eec19d4f81f2b602df79435d4
[simantics/platform.git] / bundles / org.simantics.simulation.ui / src / org / simantics / simulation / ui / handlers / TimerContribution.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
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
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.simulation.ui.handlers;
13
14 import java.util.concurrent.ScheduledFuture;
15 import java.util.concurrent.TimeUnit;
16
17 import org.eclipse.jface.action.IContributionItem;
18 import org.eclipse.jface.resource.ColorDescriptor;
19 import org.eclipse.jface.resource.JFaceResources;
20 import org.eclipse.jface.resource.LocalResourceManager;
21 import org.eclipse.jface.resource.ResourceManager;
22 import org.eclipse.swt.SWT;
23 import org.eclipse.swt.graphics.Color;
24 import org.eclipse.swt.graphics.Point;
25 import org.eclipse.swt.graphics.RGB;
26 import org.eclipse.swt.widgets.Event;
27 import org.eclipse.swt.widgets.Listener;
28 import org.eclipse.swt.widgets.Text;
29 import org.eclipse.swt.widgets.ToolBar;
30 import org.eclipse.swt.widgets.ToolItem;
31 import org.eclipse.ui.PlatformUI;
32 import org.eclipse.ui.actions.CompoundContributionItem;
33 import org.simantics.project.IProject;
34 import org.simantics.simulation.experiment.ExperimentState;
35 import org.simantics.simulation.experiment.IDynamicExperiment;
36 import org.simantics.simulation.experiment.IDynamicExperimentListener;
37 import org.simantics.simulation.experiment.IExperiment;
38 import org.simantics.simulation.experiment.IExperimentListener;
39 import org.simantics.simulation.experiment.SimulationTimeUtil;
40 import org.simantics.simulation.project.IExperimentManager;
41 import org.simantics.simulation.project.IExperimentManagerListener;
42 import org.simantics.ui.SimanticsUI;
43 import org.simantics.utils.threads.ThreadUtils;
44
45
46 public class TimerContribution extends CompoundContributionItem {
47
48     private static final long LABEL_UPDATE_MIN_PERIOD_MS = 100;
49
50     enum Mode {
51         HMS,
52         SECONDS;
53         Mode next() {
54             switch (this) {
55                 case HMS: return SECONDS;
56                 case SECONDS: return HMS;
57                 default: return HMS;
58             }
59         }
60     }
61
62     boolean              disposed = false;
63     Text                 label;
64     int                  width;
65     double               time     = 0.0;
66     private Mode         mode     = Mode.HMS;
67     private ToolItem     ti;
68     private IExperimentManager experimentManager;
69     private IExperimentManagerListener experimentManagerListener;
70     private ExperimentState currentState;
71
72     private ResourceManager            resourceManager;
73
74     private static ColorDescriptor     RUNNING_BG = ColorDescriptor.createFrom(new RGB(0, 128, 0));
75     private static ColorDescriptor     RUNNING_FG = ColorDescriptor.createFrom(new RGB(255, 255, 255));
76
77     public TimerContribution() {
78         super("org.simantics.simulation.ui.timer");
79     }
80
81     @Override
82     protected IContributionItem[] getContributionItems() {
83         return new IContributionItem[0];
84     }
85
86     String getTime() {
87         if (mode == Mode.SECONDS)
88             return SimulationTimeUtil.formatSeconds(time);
89         return SimulationTimeUtil.formatHMSS(time);
90     }
91
92     @Override
93     public void fill(final ToolBar parent, final int index) {
94         //System.out.println(this + "(" + System.identityHashCode(this) + ") FILL");
95
96         IProject project = SimanticsUI.peekProject();
97         if (project == null)
98             return;
99
100         IExperimentManager manager = project.getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER);
101         if(manager == null)
102             return;
103
104         IExperiment active = manager.getActiveExperiment();
105         if (!(active instanceof IDynamicExperiment))
106             return;
107
108         //System.out.println(this + "(" + System.identityHashCode(this) + ") got DynamicExperiment: " + active);
109
110         ti = new ToolItem(parent, SWT.SEPARATOR, index);
111         ti.setText("Simulation Timer");
112         ti.setToolTipText("Simulation Timer");
113         label = new Text(parent, SWT.BORDER | SWT.CENTER | SWT.READ_ONLY);
114         label.setText(getTime());
115
116         this.resourceManager = new LocalResourceManager(JFaceResources.getResources(), label);
117
118         updateTooltip();
119
120         Listener labelListener = new Listener() {
121             boolean pressed = false;
122             boolean inside = false;
123             @Override
124             public void handleEvent(Event event) {
125                 switch (event.type) {
126                     case SWT.MouseDown:
127                         if (inside && (event.button == 1 || event.button == 2))
128                             pressed = true;
129                         break;
130                     case SWT.MouseUp:
131                         if (pressed && inside) {
132                             pressed = false;
133                             toggleMode();
134                         }
135                         break;
136                     case SWT.MouseEnter:
137                         inside = true;
138                         break;
139                     case SWT.MouseExit:
140                         inside = false;
141                         break;
142                 }
143             }
144         };
145         label.addListener(SWT.MouseDown, labelListener);
146         label.addListener(SWT.MouseEnter, labelListener);
147         label.addListener(SWT.MouseExit, labelListener);
148         label.addListener(SWT.MouseUp, labelListener);
149
150         width = label.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x;
151         ti.setWidth(width);
152         ti.setControl(label);
153
154         if (currentState != null)
155             setLabelVisualsByState(currentState);
156
157         attachToExperimentManager(manager);
158     }
159
160     private void attachToExperimentManager(final IExperimentManager manager) {
161         if (experimentManager != null) {
162             if (experimentManager.equals(manager))
163                 return;
164             experimentManager.removeListener(experimentManagerListener);
165         }
166         if (manager == null)
167             return;
168
169         //System.out.println(this + "(" + System.identityHashCode(this) + ") ATTACH TO EXPERIMENT MANAGER " + manager);
170
171         experimentManagerListener = new IExperimentManagerListener() {
172             IDynamicExperiment currentExperiment;
173             IExperimentListener currentListener;
174
175             @Override
176             public void managerDisposed() {
177                 manager.removeListener(this);
178             }
179             @Override
180             public void activeExperimentUnloaded() {
181                 attachToExperiment(null);
182             }
183             @Override
184             public void activeExperimentLoaded(IExperiment experiment) {
185                 attachToExperiment(experiment);
186             }
187             synchronized void attachToExperiment(final IExperiment experiment) {
188                 if (currentExperiment != null) {
189                     currentExperiment.removeListener(currentListener);
190                     currentExperiment = null;
191                     currentListener = null;
192                 }
193
194                 if (experiment == null)
195                     return;
196                 if (!(experiment instanceof IDynamicExperiment))
197                     return;
198
199                 IDynamicExperiment dynExp = (IDynamicExperiment) experiment;
200                 //System.out.println(TimerContribution.this + "(" + System.identityHashCode(TimerContribution.this) + ") ATTACH TO EXPERIMENT " + dynExp);
201
202                 IDynamicExperimentListener listener = new IDynamicExperimentListener() {
203                     final IExperimentListener _this = this;
204                     long lastUpdateTime = 0;
205                     ScheduledFuture<?> timedUpdate = null;
206                     ExperimentState lastState = null;
207                     @Override
208                     public void timeChanged(double newTime) {
209                         //System.out.println(this + ".timeChanged: " + newTime);
210                         time = newTime;
211
212                         ScheduledFuture<?> f = timedUpdate;
213                         if (f != null && !f.isDone())
214                             return;
215
216                         long timeSinceLastUpdate = System.currentTimeMillis() - lastUpdateTime;
217
218                         if (timeSinceLastUpdate > LABEL_UPDATE_MIN_PERIOD_MS) {
219                             scheduleLabelUpdate();
220                         } else {
221                             timedUpdate = ThreadUtils.getNonBlockingWorkExecutor().schedule(new Runnable() {
222                                 @Override
223                                 public void run() {
224                                     scheduleLabelUpdate();
225                                 }
226                             }, LABEL_UPDATE_MIN_PERIOD_MS - timeSinceLastUpdate, TimeUnit.MILLISECONDS);
227                         }
228                     }
229                     private void scheduleLabelUpdate() {
230                         lastUpdateTime = System.currentTimeMillis();
231                         timedUpdate = null;
232
233                         PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
234                             @Override
235                             public void run() {
236                                 //System.out.println("updating time label: " + time);
237                                 //System.out.println("label isdisposed: " + label.isDisposed());
238                                 if (!label.isDisposed())
239                                     updateLabel();
240
241                                 if (lastState != currentState) {
242                                     setLabelVisualsByState(currentState);
243                                     lastState = currentState;
244                                 }
245                             }
246                         });
247                     }
248                     @Override
249                     public void stateChanged(ExperimentState state) {
250                         //System.out.println("TimerContribution: state changed: " + state);
251                         currentState = state;
252                         if (state == ExperimentState.DISPOSED)
253                             experiment.removeListener(_this);
254                         else
255                             scheduleLabelUpdate();
256                     }
257                 };
258                 experiment.addListener(listener);
259
260                 currentExperiment = dynExp;
261                 currentListener = listener;
262             }
263         };
264
265         experimentManager = manager;
266         manager.addListener(experimentManagerListener);
267     }
268
269     private void toggleMode() {
270         mode = mode.next();
271         if (label.isDisposed())
272             return;
273         updateLabel();
274         updateTooltip();
275     }
276
277     private void updateTooltip() {
278         if (label.isDisposed())
279             return;
280         switch (mode) {
281             case HMS:
282                 label.setToolTipText("Shows simulation time in HMS");
283                 break;
284             case SECONDS:
285                 label.setToolTipText("Shows simulation time in seconds");
286                 break;
287         }
288     }
289
290     private void updateLabel() {
291         // Try to keep selection.
292         Point selection = label.getSelection();
293         String oldText = label.getText();
294         String newText = getTime();
295         if (selection.y == oldText.length())
296             selection.y = newText.length();
297         else
298             selection.y = Math.min(selection.y, newText.length());
299
300         label.setText(newText);
301         label.setSelection(selection);
302         int newWidth = label.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x;
303         if (newWidth != width) {
304             label.pack();
305             width = newWidth;
306             if (!ti.isDisposed()) {
307                 ti.setWidth(width);
308                 if (!ti.getParent().isDisposed())
309                     ti.getParent().pack();
310             }
311         }
312     }
313
314     @Override
315     public void dispose() {
316         disposed = true;
317         //System.out.println(this + "(" + System.identityHashCode(this) + ") DISPOSE");
318         attachToExperimentManager(null);
319     }
320
321     @Override
322     public boolean isDynamic() {
323         return true;
324     }
325
326     /**
327      * @param currentState
328      * @thread SWT
329      */
330     private void setLabelVisualsByState(ExperimentState currentState) {
331         if (label.isDisposed())
332             return;
333         switch (currentState) {
334             case RUNNING:
335                 label.setBackground((Color) resourceManager.get(RUNNING_BG));
336                 label.setForeground((Color) resourceManager.get(RUNNING_FG));
337                 //label.setFont((Font) resourceManager.get(FontDescriptor.createFrom(label.getFont()).setStyle(SWT.BOLD)));
338                 label.setEnabled(true);
339                 break;
340             case STOPPED:
341                 label.setBackground(null);
342                 label.setForeground(null);
343                 label.setFont(null);
344                 label.setEnabled(true);
345                 break;
346             case INITIALIZING:
347                 label.setBackground(null);
348                 label.setForeground(null);
349                 label.setFont(null);
350                 label.setEnabled(false);
351                 break;
352         }
353     }
354
355 }