]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.simulation.ui/src/org/simantics/simulation/ui/handlers/TimerContribution.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.simulation.ui / src / org / simantics / simulation / ui / handlers / TimerContribution.java
diff --git a/bundles/org.simantics.simulation.ui/src/org/simantics/simulation/ui/handlers/TimerContribution.java b/bundles/org.simantics.simulation.ui/src/org/simantics/simulation/ui/handlers/TimerContribution.java
new file mode 100644 (file)
index 0000000..3cee539
--- /dev/null
@@ -0,0 +1,355 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 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
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.simulation.ui.handlers;\r
+\r
+import java.util.concurrent.ScheduledFuture;\r
+import java.util.concurrent.TimeUnit;\r
+\r
+import org.eclipse.jface.action.IContributionItem;\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.Event;\r
+import org.eclipse.swt.widgets.Listener;\r
+import org.eclipse.swt.widgets.Text;\r
+import org.eclipse.swt.widgets.ToolBar;\r
+import org.eclipse.swt.widgets.ToolItem;\r
+import org.eclipse.ui.PlatformUI;\r
+import org.eclipse.ui.actions.CompoundContributionItem;\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
+public class TimerContribution extends CompoundContributionItem {\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
+    int                  width;\r
+    double               time     = 0.0;\r
+    private Mode         mode     = Mode.HMS;\r
+    private ToolItem     ti;\r
+    private IExperimentManager experimentManager;\r
+    private IExperimentManagerListener experimentManagerListener;\r
+    private ExperimentState currentState;\r
+\r
+    private ResourceManager            resourceManager;\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
+    public TimerContribution() {\r
+        super("org.simantics.simulation.ui.timer");\r
+    }\r
+\r
+    @Override\r
+    protected IContributionItem[] getContributionItems() {\r
+        return new IContributionItem[0];\r
+    }\r
+\r
+    String getTime() {\r
+        if (mode == Mode.SECONDS)\r
+            return SimulationTimeUtil.formatSeconds(time);\r
+        return SimulationTimeUtil.formatHMSS(time);\r
+    }\r
+\r
+    @Override\r
+    public void fill(final ToolBar parent, final int index) {\r
+        //System.out.println(this + "(" + System.identityHashCode(this) + ") FILL");\r
+\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
+        IExperiment active = manager.getActiveExperiment();\r
+        if (!(active instanceof IDynamicExperiment))\r
+            return;\r
+\r
+        //System.out.println(this + "(" + System.identityHashCode(this) + ") got DynamicExperiment: " + active);\r
+\r
+        ti = new ToolItem(parent, SWT.SEPARATOR, index);\r
+        ti.setText("Simulation Timer");\r
+        ti.setToolTipText("Simulation Timer");\r
+        label = new Text(parent, SWT.BORDER | SWT.CENTER | SWT.READ_ONLY);\r
+        label.setText(getTime());\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
+        width = label.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x;\r
+        ti.setWidth(width);\r
+        ti.setControl(label);\r
+\r
+        if (currentState != null)\r
+            setLabelVisualsByState(currentState);\r
+\r
+        attachToExperimentManager(manager);\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 == null)\r
+                    return;\r
+                if (!(experiment instanceof IDynamicExperiment))\r
+                    return;\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(new Runnable() {\r
+                                @Override\r
+                                public void run() {\r
+                                    scheduleLabelUpdate();\r
+                                }\r
+                            }, LABEL_UPDATE_MIN_PERIOD_MS - timeSinceLastUpdate, TimeUnit.MILLISECONDS);\r
+                        }\r
+                    }\r
+                    private void scheduleLabelUpdate() {\r
+                        lastUpdateTime = System.currentTimeMillis();\r
+                        timedUpdate = null;\r
+\r
+                        PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {\r
+                            @Override\r
+                            public void run() {\r
+                                //System.out.println("updating time label: " + time);\r
+                                //System.out.println("label isdisposed: " + label.isDisposed());\r
+                                if (!label.isDisposed())\r
+                                    updateLabel();\r
+\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
+            return;\r
+        updateLabel();\r
+        updateTooltip();\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
+        int newWidth = label.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x;\r
+        if (newWidth != width) {\r
+            label.pack();\r
+            width = newWidth;\r
+            if (!ti.isDisposed()) {\r
+                ti.setWidth(width);\r
+                if (!ti.getParent().isDisposed())\r
+                    ti.getParent().pack();\r
+            }\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public void dispose() {\r
+        disposed = true;\r
+        //System.out.println(this + "(" + System.identityHashCode(this) + ") DISPOSE");\r
+        attachToExperimentManager(null);\r
+    }\r
+\r
+    @Override\r
+    public boolean isDynamic() {\r
+        return true;\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
+                label.setBackground(null);\r
+                label.setForeground(null);\r
+                label.setFont(null);\r
+                label.setEnabled(false);\r
+                break;\r
+        }\r
+    }\r
+\r
+}\r