X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.simulation.ui%2Fsrc%2Forg%2Fsimantics%2Fsimulation%2Fui%2Fhandlers%2FTimerContribution.java;fp=bundles%2Forg.simantics.simulation.ui%2Fsrc%2Forg%2Fsimantics%2Fsimulation%2Fui%2Fhandlers%2FTimerContribution.java;h=3cee539a46324ae84c78a5ee62cb7dc50b6eeddd;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git 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 index 000000000..3cee539a4 --- /dev/null +++ b/bundles/org.simantics.simulation.ui/src/org/simantics/simulation/ui/handlers/TimerContribution.java @@ -0,0 +1,355 @@ +/******************************************************************************* + * 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.simulation.ui.handlers; + +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jface.action.IContributionItem; +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.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.ToolItem; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.actions.CompoundContributionItem; +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.ui.SimanticsUI; +import org.simantics.utils.threads.ThreadUtils; + + +public class TimerContribution extends CompoundContributionItem { + + 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; + int width; + double time = 0.0; + private Mode mode = Mode.HMS; + private ToolItem ti; + private IExperimentManager experimentManager; + private IExperimentManagerListener experimentManagerListener; + private ExperimentState currentState; + + private ResourceManager resourceManager; + + private static ColorDescriptor RUNNING_BG = ColorDescriptor.createFrom(new RGB(0, 128, 0)); + private static ColorDescriptor RUNNING_FG = ColorDescriptor.createFrom(new RGB(255, 255, 255)); + + public TimerContribution() { + super("org.simantics.simulation.ui.timer"); + } + + @Override + protected IContributionItem[] getContributionItems() { + return new IContributionItem[0]; + } + + String getTime() { + if (mode == Mode.SECONDS) + return SimulationTimeUtil.formatSeconds(time); + return SimulationTimeUtil.formatHMSS(time); + } + + @Override + public void fill(final ToolBar parent, final int index) { + //System.out.println(this + "(" + System.identityHashCode(this) + ") FILL"); + + IProject project = SimanticsUI.peekProject(); + if (project == null) + return; + + IExperimentManager manager = project.getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER); + if(manager == null) + return; + + IExperiment active = manager.getActiveExperiment(); + if (!(active instanceof IDynamicExperiment)) + return; + + //System.out.println(this + "(" + System.identityHashCode(this) + ") got DynamicExperiment: " + active); + + ti = new ToolItem(parent, SWT.SEPARATOR, index); + ti.setText("Simulation Timer"); + ti.setToolTipText("Simulation Timer"); + label = new Text(parent, SWT.BORDER | SWT.CENTER | SWT.READ_ONLY); + label.setText(getTime()); + + 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); + + width = label.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x; + ti.setWidth(width); + ti.setControl(label); + + if (currentState != null) + setLabelVisualsByState(currentState); + + attachToExperimentManager(manager); + } + + 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 == null) + return; + if (!(experiment instanceof IDynamicExperiment)) + 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(new Runnable() { + @Override + public void run() { + scheduleLabelUpdate(); + } + }, LABEL_UPDATE_MIN_PERIOD_MS - timeSinceLastUpdate, TimeUnit.MILLISECONDS); + } + } + private void scheduleLabelUpdate() { + lastUpdateTime = System.currentTimeMillis(); + timedUpdate = null; + + PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + //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()) + return; + updateLabel(); + updateTooltip(); + } + + 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); + int newWidth = label.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x; + if (newWidth != width) { + label.pack(); + width = newWidth; + if (!ti.isDisposed()) { + ti.setWidth(width); + if (!ti.getParent().isDisposed()) + ti.getParent().pack(); + } + } + } + + @Override + public void dispose() { + disposed = true; + //System.out.println(this + "(" + System.identityHashCode(this) + ") DISPOSE"); + attachToExperimentManager(null); + } + + @Override + public boolean isDynamic() { + return true; + } + + /** + * @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: + label.setBackground(null); + label.setForeground(null); + label.setFont(null); + label.setEnabled(false); + break; + } + } + +}