-/*******************************************************************************\r
- * Copyright (c) 2015, 2016 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * Semantum Oy - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.simulation.ui.handlers.e4;\r
-\r
-import java.util.concurrent.ScheduledFuture;\r
-import java.util.concurrent.TimeUnit;\r
-\r
-import javax.annotation.PostConstruct;\r
-import javax.annotation.PreDestroy;\r
-import javax.inject.Inject;\r
-\r
-import org.eclipse.core.runtime.preferences.IEclipsePreferences;\r
-import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;\r
-import org.eclipse.e4.core.di.annotations.Optional;\r
-import org.eclipse.e4.core.di.extensions.Preference;\r
-import org.eclipse.e4.ui.di.UISynchronize;\r
-import org.eclipse.e4.ui.model.application.ui.menu.MToolControl;\r
-import org.eclipse.jface.resource.ColorDescriptor;\r
-import org.eclipse.jface.resource.JFaceResources;\r
-import org.eclipse.jface.resource.LocalResourceManager;\r
-import org.eclipse.jface.resource.ResourceManager;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.graphics.Color;\r
-import org.eclipse.swt.graphics.Point;\r
-import org.eclipse.swt.graphics.RGB;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Event;\r
-import org.eclipse.swt.widgets.Listener;\r
-import org.eclipse.swt.widgets.Text;\r
-import org.simantics.databoard.util.ObjectUtils;\r
-import org.simantics.project.IProject;\r
-import org.simantics.simulation.experiment.ExperimentState;\r
-import org.simantics.simulation.experiment.IDynamicExperiment;\r
-import org.simantics.simulation.experiment.IDynamicExperimentListener;\r
-import org.simantics.simulation.experiment.IExperiment;\r
-import org.simantics.simulation.experiment.IExperimentListener;\r
-import org.simantics.simulation.experiment.SimulationTimeUtil;\r
-import org.simantics.simulation.project.IExperimentManager;\r
-import org.simantics.simulation.project.IExperimentManagerListener;\r
-import org.simantics.ui.SimanticsUI;\r
-import org.simantics.utils.threads.ThreadUtils;\r
-\r
-/**\r
- * E4-version of the old\r
- * {@link org.simantics.simulation.ui.handlers.TimerContribution}.\r
- * \r
- * <p>\r
- * Bound to org.simantics.chart/chart.timeformat preference for the used time\r
- * format. This is not the nicest of solutions since it makes the\r
- * <code>org.simantics.simulation.ui</code> plug-in depend on the\r
- * <code>org.simantics.charts</code> plug-in. However the binding is optional\r
- * and therefore the thin dependency is acceptable for now.\r
- * \r
- * @author Jani Simomaa / Semantum Oy\r
- * @author Tuukka Lehtonen / Semantum Oy\r
- * @since 1.22\r
- */\r
-public class TimerContribution {\r
-\r
- private static final String PREF_CHART_BUNDLE_ID = "org.simantics.charts";\r
- private static final String PREF_CHART_TIMEFORMAT = "chart.timeformat";\r
-\r
- private static final long LABEL_UPDATE_MIN_PERIOD_MS = 100;\r
-\r
- enum Mode {\r
- HMS,\r
- SECONDS;\r
- Mode next() {\r
- switch (this) {\r
- case HMS: return SECONDS;\r
- case SECONDS: return HMS;\r
- default: return HMS;\r
- }\r
- }\r
- }\r
-\r
- boolean disposed = false;\r
- Text label;\r
- Point size;\r
- double time = 0.0;\r
- private Mode mode = Mode.HMS;\r
-\r
- private IExperimentManager experimentManager;\r
- private IExperimentManagerListener experimentManagerListener;\r
- private ExperimentState currentState;\r
-\r
- private ResourceManager resourceManager;\r
-\r
- @Inject\r
- private UISynchronize uisync;\r
-\r
- /**\r
- * For listening to the current chart time format preference.\r
- */\r
- @Inject\r
- @Optional\r
- @Preference(nodePath = PREF_CHART_BUNDLE_ID)\r
- private IEclipsePreferences chartPreferences;\r
-\r
- private static String toTimeFormatPreference(Mode mode) {\r
- switch (mode) {\r
- case SECONDS: return "Decimal";\r
- case HMS:\r
- default: return "Time";\r
- }\r
- }\r
-\r
- private static Mode toMode(String timeFormat) {\r
- if (timeFormat == null)\r
- return Mode.HMS;\r
- switch (timeFormat) {\r
- case "Decimal": return Mode.SECONDS;\r
- case "Time":\r
- default: return Mode.HMS;\r
- }\r
- }\r
-\r
- private IPreferenceChangeListener chartTimeFormatListener = event -> {\r
- if (PREF_CHART_TIMEFORMAT.equals(event.getKey())) {\r
- Mode newMode = toMode((String) event.getNewValue());\r
- if (newMode != mode) {\r
- mode = newMode;\r
- uisync.asyncExec(() -> {\r
- if (!label.isDisposed()) {\r
- updateLabel();\r
- updateTooltip();\r
- }\r
- });\r
- }\r
- }\r
- };\r
-\r
- private static ColorDescriptor RUNNING_BG = ColorDescriptor.createFrom(new RGB(0, 128, 0));\r
- private static ColorDescriptor RUNNING_FG = ColorDescriptor.createFrom(new RGB(255, 255, 255));\r
-\r
- @PostConstruct\r
- public void createControls(Composite parent, MToolControl toolControl) {\r
- IProject project = SimanticsUI.peekProject();\r
- if (project == null)\r
- return;\r
-\r
- IExperimentManager manager = project.getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER);\r
- if(manager == null)\r
- return;\r
-\r
- label = new Text(parent, SWT.BORDER | SWT.CENTER | SWT.READ_ONLY);\r
- label.setEnabled(false);\r
- label.setText(getTime());\r
- label.setToolTipText("Simulation Timer");\r
-\r
- this.resourceManager = new LocalResourceManager(JFaceResources.getResources(), label);\r
-\r
- updateTooltip();\r
-\r
- Listener labelListener = new Listener() {\r
- boolean pressed = false;\r
- boolean inside = false;\r
- @Override\r
- public void handleEvent(Event event) {\r
- switch (event.type) {\r
- case SWT.MouseDown:\r
- if (inside && (event.button == 1 || event.button == 2))\r
- pressed = true;\r
- break;\r
- case SWT.MouseUp:\r
- if (pressed && inside) {\r
- pressed = false;\r
- toggleMode();\r
- }\r
- break;\r
- case SWT.MouseEnter:\r
- inside = true;\r
- break;\r
- case SWT.MouseExit:\r
- inside = false;\r
- break;\r
- }\r
- }\r
- };\r
- label.addListener(SWT.MouseDown, labelListener);\r
- label.addListener(SWT.MouseEnter, labelListener);\r
- label.addListener(SWT.MouseExit, labelListener);\r
- label.addListener(SWT.MouseUp, labelListener);\r
-\r
- size = label.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);\r
- if (currentState != null)\r
- setLabelVisualsByState(currentState);\r
-\r
- attachToExperimentManager(manager);\r
-\r
- if (chartPreferences != null) {\r
- chartPreferences.addPreferenceChangeListener(chartTimeFormatListener);\r
- mode = toMode((String) chartPreferences.get(PREF_CHART_TIMEFORMAT, null));\r
- }\r
- }\r
-\r
- @PreDestroy\r
- public void destroy() {\r
- if (chartPreferences != null) {\r
- chartPreferences.removePreferenceChangeListener(chartTimeFormatListener);\r
- }\r
- }\r
-\r
- private void attachToExperimentManager(final IExperimentManager manager) {\r
- if (experimentManager != null) {\r
- if (experimentManager.equals(manager))\r
- return;\r
- experimentManager.removeListener(experimentManagerListener);\r
- }\r
- if (manager == null)\r
- return;\r
-\r
- //System.out.println(this + "(" + System.identityHashCode(this) + ") ATTACH TO EXPERIMENT MANAGER " + manager);\r
-\r
- experimentManagerListener = new IExperimentManagerListener() {\r
- IDynamicExperiment currentExperiment;\r
- IExperimentListener currentListener;\r
-\r
- @Override\r
- public void managerDisposed() {\r
- manager.removeListener(this);\r
- }\r
- @Override\r
- public void activeExperimentUnloaded() {\r
- attachToExperiment(null);\r
- }\r
- @Override\r
- public void activeExperimentLoaded(IExperiment experiment) {\r
- attachToExperiment(experiment);\r
- }\r
- synchronized void attachToExperiment(final IExperiment experiment) {\r
- if (currentExperiment != null) {\r
- currentExperiment.removeListener(currentListener);\r
- currentExperiment = null;\r
- currentListener = null;\r
- }\r
-\r
- if (!(experiment instanceof IDynamicExperiment)) {\r
- // Ensure that the timer text value is reset to zero.\r
- time = 0;\r
- uisync.asyncExec(() -> {\r
- if (!label.isDisposed()) {\r
- updateLabel();\r
- setLabelVisualsByState(ExperimentState.DISPOSED);\r
- }\r
- });\r
- return;\r
- }\r
-\r
- IDynamicExperiment dynExp = (IDynamicExperiment) experiment;\r
- //System.out.println(TimerContribution.this + "(" + System.identityHashCode(TimerContribution.this) + ") ATTACH TO EXPERIMENT " + dynExp);\r
-\r
- IDynamicExperimentListener listener = new IDynamicExperimentListener() {\r
- final IExperimentListener _this = this;\r
- long lastUpdateTime = 0;\r
- ScheduledFuture<?> timedUpdate = null;\r
- ExperimentState lastState = null;\r
- @Override\r
- public void timeChanged(double newTime) {\r
- //System.out.println(this + ".timeChanged: " + newTime);\r
- time = newTime;\r
-\r
- ScheduledFuture<?> f = timedUpdate;\r
- if (f != null && !f.isDone())\r
- return;\r
-\r
- long timeSinceLastUpdate = System.currentTimeMillis() - lastUpdateTime;\r
-\r
- if (timeSinceLastUpdate > LABEL_UPDATE_MIN_PERIOD_MS) {\r
- scheduleLabelUpdate();\r
- } else {\r
- timedUpdate = ThreadUtils.getNonBlockingWorkExecutor().schedule(\r
- () -> scheduleLabelUpdate(),\r
- LABEL_UPDATE_MIN_PERIOD_MS - timeSinceLastUpdate,\r
- TimeUnit.MILLISECONDS);\r
- }\r
- }\r
- private void scheduleLabelUpdate() {\r
- lastUpdateTime = System.currentTimeMillis();\r
- timedUpdate = null;\r
-\r
- uisync.asyncExec(() -> {\r
- //System.out.println("updating time label: " + time);\r
- //System.out.println("label isdisposed: " + label.isDisposed());\r
- if (!label.isDisposed()) {\r
- updateLabel();\r
- if (lastState != currentState) {\r
- setLabelVisualsByState(currentState);\r
- lastState = currentState;\r
- }\r
- }\r
- });\r
- }\r
- @Override\r
- public void stateChanged(ExperimentState state) {\r
- //System.out.println("TimerContribution: state changed: " + state);\r
- currentState = state;\r
- if (state == ExperimentState.DISPOSED)\r
- experiment.removeListener(_this);\r
- else\r
- scheduleLabelUpdate();\r
- }\r
- };\r
- experiment.addListener(listener);\r
-\r
- currentExperiment = dynExp;\r
- currentListener = listener;\r
- }\r
- };\r
-\r
- experimentManager = manager;\r
- manager.addListener(experimentManagerListener);\r
- }\r
-\r
- private void toggleMode() {\r
- mode = mode.next();\r
- if (!label.isDisposed()) {\r
- updateLabel();\r
- updateTooltip();\r
- setTimeFormatPreference(mode);\r
- }\r
- }\r
-\r
- private void setTimeFormatPreference(Mode mode) {\r
- if (chartPreferences != null) {\r
- chartPreferences.put(PREF_CHART_TIMEFORMAT, toTimeFormatPreference(mode));\r
- }\r
- }\r
-\r
- private void updateTooltip() {\r
- if (label.isDisposed())\r
- return;\r
- switch (mode) {\r
- case HMS:\r
- label.setToolTipText("Shows simulation time in HMS");\r
- break;\r
- case SECONDS:\r
- label.setToolTipText("Shows simulation time in seconds");\r
- break;\r
- }\r
- }\r
-\r
- private void updateLabel() {\r
- // Try to keep selection.\r
- Point selection = label.getSelection();\r
- String oldText = label.getText();\r
- String newText = getTime();\r
- if (selection.y == oldText.length())\r
- selection.y = newText.length();\r
- else\r
- selection.y = Math.min(selection.y, newText.length());\r
-\r
- label.setText(newText);\r
- label.setSelection(selection);\r
- Point newSize = label.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);\r
- if (!ObjectUtils.objectEquals(newSize, size)) {\r
- label.setSize(newSize);\r
- size = newSize;\r
- Composite parent = label.getParent();\r
- if (parent != null) {\r
- parent.layout();\r
- }\r
- }\r
- }\r
-\r
- /**\r
- * @param currentState\r
- * @thread SWT\r
- */\r
- private void setLabelVisualsByState(ExperimentState currentState) {\r
- if (label.isDisposed())\r
- return;\r
- switch (currentState) {\r
- case RUNNING:\r
- label.setBackground((Color) resourceManager.get(RUNNING_BG));\r
- label.setForeground((Color) resourceManager.get(RUNNING_FG));\r
- //label.setFont((Font) resourceManager.get(FontDescriptor.createFrom(label.getFont()).setStyle(SWT.BOLD)));\r
- label.setEnabled(true);\r
- break;\r
- case STOPPED:\r
- label.setBackground(null);\r
- label.setForeground(null);\r
- label.setFont(null);\r
- label.setEnabled(true);\r
- break;\r
- case INITIALIZING:\r
- case DISPOSED:\r
- label.setBackground(null);\r
- label.setForeground(null);\r
- label.setFont(null);\r
- label.setEnabled(false);\r
- break;\r
- }\r
- }\r
-\r
- private String getTime() {\r
- if (mode == Mode.SECONDS)\r
- return SimulationTimeUtil.formatSeconds(time);\r
- return SimulationTimeUtil.formatHMSS(time);\r
- }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2015, 2016 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:
+ * Semantum Oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.simulation.ui.handlers.e4;
+
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.core.di.extensions.Preference;
+import org.eclipse.e4.ui.di.UISynchronize;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolControl;
+import org.eclipse.jface.resource.ColorDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+import org.simantics.Simantics;
+import org.simantics.databoard.util.ObjectUtils;
+import org.simantics.project.IProject;
+import org.simantics.simulation.experiment.ExperimentState;
+import org.simantics.simulation.experiment.IDynamicExperiment;
+import org.simantics.simulation.experiment.IDynamicExperimentListener;
+import org.simantics.simulation.experiment.IExperiment;
+import org.simantics.simulation.experiment.IExperimentListener;
+import org.simantics.simulation.experiment.SimulationTimeUtil;
+import org.simantics.simulation.project.IExperimentManager;
+import org.simantics.simulation.project.IExperimentManagerListener;
+import org.simantics.utils.threads.ThreadUtils;
+
+/**
+ * E4-version of the old
+ * {@link org.simantics.simulation.ui.handlers.TimerContribution}.
+ *
+ * <p>
+ * Bound to org.simantics.chart/chart.timeformat preference for the used time
+ * format. This is not the nicest of solutions since it makes the
+ * <code>org.simantics.simulation.ui</code> plug-in depend on the
+ * <code>org.simantics.charts</code> plug-in. However the binding is optional
+ * and therefore the thin dependency is acceptable for now.
+ *
+ * @author Jani Simomaa / Semantum Oy
+ * @author Tuukka Lehtonen / Semantum Oy
+ * @since 1.22
+ */
+public class TimerContribution {
+
+ private static final String PREF_CHART_BUNDLE_ID = "org.simantics.charts";
+ private static final String PREF_CHART_TIMEFORMAT = "chart.timeformat";
+
+ private static final long LABEL_UPDATE_MIN_PERIOD_MS = 100;
+
+ enum Mode {
+ HMS,
+ SECONDS;
+ Mode next() {
+ switch (this) {
+ case HMS: return SECONDS;
+ case SECONDS: return HMS;
+ default: return HMS;
+ }
+ }
+ }
+
+ boolean disposed = false;
+ Text label;
+ Point size;
+ double time = 0.0;
+ private Mode mode = Mode.HMS;
+
+ private IExperimentManager experimentManager;
+ private IExperimentManagerListener experimentManagerListener;
+ private ExperimentState currentState;
+
+ private ResourceManager resourceManager;
+
+ @Inject
+ private UISynchronize uisync;
+
+ /**
+ * For listening to the current chart time format preference.
+ */
+ @Inject
+ @Optional
+ @Preference(nodePath = PREF_CHART_BUNDLE_ID)
+ private IEclipsePreferences chartPreferences;
+
+ private static String toTimeFormatPreference(Mode mode) {
+ switch (mode) {
+ case SECONDS: return "Decimal";
+ case HMS:
+ default: return "Time";
+ }
+ }
+
+ private static Mode toMode(String timeFormat) {
+ if (timeFormat == null)
+ return Mode.HMS;
+ switch (timeFormat) {
+ case "Decimal": return Mode.SECONDS;
+ case "Time":
+ default: return Mode.HMS;
+ }
+ }
+
+ private IPreferenceChangeListener chartTimeFormatListener = event -> {
+ if (PREF_CHART_TIMEFORMAT.equals(event.getKey())) {
+ Mode newMode = toMode((String) event.getNewValue());
+ if (newMode != mode) {
+ mode = newMode;
+ uisync.asyncExec(() -> {
+ if (!label.isDisposed()) {
+ updateLabel();
+ updateTooltip();
+ }
+ });
+ }
+ }
+ };
+
+ private static ColorDescriptor RUNNING_BG = ColorDescriptor.createFrom(new RGB(0, 128, 0));
+ private static ColorDescriptor RUNNING_FG = ColorDescriptor.createFrom(new RGB(255, 255, 255));
+
+ @PostConstruct
+ public void createControls(Composite parent, MToolControl toolControl) {
+ IProject project = Simantics.peekProject();
+ if (project == null)
+ return;
+
+ IExperimentManager manager = project.getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER);
+ if(manager == null)
+ return;
+
+ label = new Text(parent, SWT.BORDER | SWT.CENTER | SWT.READ_ONLY);
+ label.setEnabled(false);
+ label.setText(getTime());
+ label.setToolTipText("Simulation Timer");
+
+ this.resourceManager = new LocalResourceManager(JFaceResources.getResources(), label);
+
+ updateTooltip();
+
+ Listener labelListener = new Listener() {
+ boolean pressed = false;
+ boolean inside = false;
+ @Override
+ public void handleEvent(Event event) {
+ switch (event.type) {
+ case SWT.MouseDown:
+ if (inside && (event.button == 1 || event.button == 2))
+ pressed = true;
+ break;
+ case SWT.MouseUp:
+ if (pressed && inside) {
+ pressed = false;
+ toggleMode();
+ }
+ break;
+ case SWT.MouseEnter:
+ inside = true;
+ break;
+ case SWT.MouseExit:
+ inside = false;
+ break;
+ }
+ }
+ };
+ label.addListener(SWT.MouseDown, labelListener);
+ label.addListener(SWT.MouseEnter, labelListener);
+ label.addListener(SWT.MouseExit, labelListener);
+ label.addListener(SWT.MouseUp, labelListener);
+
+ size = label.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
+ if (currentState != null)
+ setLabelVisualsByState(currentState);
+
+ attachToExperimentManager(manager);
+
+ if (chartPreferences != null) {
+ chartPreferences.addPreferenceChangeListener(chartTimeFormatListener);
+ mode = toMode((String) chartPreferences.get(PREF_CHART_TIMEFORMAT, null));
+ }
+ }
+
+ @PreDestroy
+ public void destroy() {
+ if (chartPreferences != null) {
+ chartPreferences.removePreferenceChangeListener(chartTimeFormatListener);
+ }
+ }
+
+ private void attachToExperimentManager(final IExperimentManager manager) {
+ if (experimentManager != null) {
+ if (experimentManager.equals(manager))
+ return;
+ experimentManager.removeListener(experimentManagerListener);
+ }
+ if (manager == null)
+ return;
+
+ //System.out.println(this + "(" + System.identityHashCode(this) + ") ATTACH TO EXPERIMENT MANAGER " + manager);
+
+ experimentManagerListener = new IExperimentManagerListener() {
+ IDynamicExperiment currentExperiment;
+ IExperimentListener currentListener;
+
+ @Override
+ public void managerDisposed() {
+ manager.removeListener(this);
+ }
+ @Override
+ public void activeExperimentUnloaded() {
+ attachToExperiment(null);
+ }
+ @Override
+ public void activeExperimentLoaded(IExperiment experiment) {
+ attachToExperiment(experiment);
+ }
+ synchronized void attachToExperiment(final IExperiment experiment) {
+ if (currentExperiment != null) {
+ currentExperiment.removeListener(currentListener);
+ currentExperiment = null;
+ currentListener = null;
+ }
+
+ if (!(experiment instanceof IDynamicExperiment)) {
+ // Ensure that the timer text value is reset to zero.
+ time = 0;
+ uisync.asyncExec(() -> {
+ if (!label.isDisposed()) {
+ updateLabel();
+ setLabelVisualsByState(ExperimentState.DISPOSED);
+ }
+ });
+ return;
+ }
+
+ IDynamicExperiment dynExp = (IDynamicExperiment) experiment;
+ //System.out.println(TimerContribution.this + "(" + System.identityHashCode(TimerContribution.this) + ") ATTACH TO EXPERIMENT " + dynExp);
+
+ IDynamicExperimentListener listener = new IDynamicExperimentListener() {
+ final IExperimentListener _this = this;
+ long lastUpdateTime = 0;
+ ScheduledFuture<?> timedUpdate = null;
+ ExperimentState lastState = null;
+ @Override
+ public void timeChanged(double newTime) {
+ //System.out.println(this + ".timeChanged: " + newTime);
+ time = newTime;
+
+ ScheduledFuture<?> f = timedUpdate;
+ if (f != null && !f.isDone())
+ return;
+
+ long timeSinceLastUpdate = System.currentTimeMillis() - lastUpdateTime;
+
+ if (timeSinceLastUpdate > LABEL_UPDATE_MIN_PERIOD_MS) {
+ scheduleLabelUpdate();
+ } else {
+ timedUpdate = ThreadUtils.getNonBlockingWorkExecutor().schedule(
+ () -> scheduleLabelUpdate(),
+ LABEL_UPDATE_MIN_PERIOD_MS - timeSinceLastUpdate,
+ TimeUnit.MILLISECONDS);
+ }
+ }
+ private void scheduleLabelUpdate() {
+ lastUpdateTime = System.currentTimeMillis();
+ timedUpdate = null;
+
+ uisync.asyncExec(() -> {
+ //System.out.println("updating time label: " + time);
+ //System.out.println("label isdisposed: " + label.isDisposed());
+ if (!label.isDisposed()) {
+ updateLabel();
+ if (lastState != currentState) {
+ setLabelVisualsByState(currentState);
+ lastState = currentState;
+ }
+ }
+ });
+ }
+ @Override
+ public void stateChanged(ExperimentState state) {
+ //System.out.println("TimerContribution: state changed: " + state);
+ currentState = state;
+ if (state == ExperimentState.DISPOSED)
+ experiment.removeListener(_this);
+ else
+ scheduleLabelUpdate();
+ }
+ };
+ experiment.addListener(listener);
+
+ currentExperiment = dynExp;
+ currentListener = listener;
+ }
+ };
+
+ experimentManager = manager;
+ manager.addListener(experimentManagerListener);
+ }
+
+ private void toggleMode() {
+ mode = mode.next();
+ if (!label.isDisposed()) {
+ updateLabel();
+ updateTooltip();
+ setTimeFormatPreference(mode);
+ }
+ }
+
+ private void setTimeFormatPreference(Mode mode) {
+ if (chartPreferences != null) {
+ chartPreferences.put(PREF_CHART_TIMEFORMAT, toTimeFormatPreference(mode));
+ }
+ }
+
+ private void updateTooltip() {
+ if (label.isDisposed())
+ return;
+ switch (mode) {
+ case HMS:
+ label.setToolTipText("Shows simulation time in HMS");
+ break;
+ case SECONDS:
+ label.setToolTipText("Shows simulation time in seconds");
+ break;
+ }
+ }
+
+ private void updateLabel() {
+ // Try to keep selection.
+ Point selection = label.getSelection();
+ String oldText = label.getText();
+ String newText = getTime();
+ if (selection.y == oldText.length())
+ selection.y = newText.length();
+ else
+ selection.y = Math.min(selection.y, newText.length());
+
+ label.setText(newText);
+ label.setSelection(selection);
+ Point newSize = label.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
+ if (!ObjectUtils.objectEquals(newSize, size)) {
+ label.setSize(newSize);
+ size = newSize;
+ Composite parent = label.getParent();
+ if (parent != null) {
+ parent.layout();
+ }
+ }
+ }
+
+ /**
+ * @param currentState
+ * @thread SWT
+ */
+ private void setLabelVisualsByState(ExperimentState currentState) {
+ if (label.isDisposed())
+ return;
+ switch (currentState) {
+ case RUNNING:
+ label.setBackground((Color) resourceManager.get(RUNNING_BG));
+ label.setForeground((Color) resourceManager.get(RUNNING_FG));
+ //label.setFont((Font) resourceManager.get(FontDescriptor.createFrom(label.getFont()).setStyle(SWT.BOLD)));
+ label.setEnabled(true);
+ break;
+ case STOPPED:
+ label.setBackground(null);
+ label.setForeground(null);
+ label.setFont(null);
+ label.setEnabled(true);
+ break;
+ case INITIALIZING:
+ case DISPOSED:
+ label.setBackground(null);
+ label.setForeground(null);
+ label.setFont(null);
+ label.setEnabled(false);
+ break;
+ }
+ }
+
+ private String getTime() {
+ if (mode == Mode.SECONDS)
+ return SimulationTimeUtil.formatSeconds(time);
+ return SimulationTimeUtil.formatHMSS(time);
+ }
+
+}