/******************************************************************************* * Copyright (c) 2012 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.modeling.ui.diagram.monitor; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import org.simantics.db.Disposable; import org.simantics.db.Resource; import org.simantics.db.procedure.Listener; import org.simantics.diagram.elements.MonitorClass; import org.simantics.g2d.canvas.Hints; import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.diagram.IDiagram; import org.simantics.g2d.element.ElementUtils; import org.simantics.g2d.element.IElement; import org.simantics.utils.threads.ThreadUtils; import org.simantics.utils.ui.ErrorLogger; /** * @author Tuukka Lehtonen */ public class MonitorListener implements Listener, Runnable, Disposable { private final Resource element; private ICanvasContext canvas; private IDiagram diagram; private final Map substitutions; private transient AtomicReference lastScheduledUpdate = null; private transient AtomicBoolean inUpdate = null; public MonitorListener(Resource element, ICanvasContext canvas, IDiagram diagram, Map substitutions) { if (element == null) throw new NullPointerException("null element"); //$NON-NLS-1$ if (canvas == null) throw new NullPointerException("null canvas"); //$NON-NLS-1$ if (diagram == null) throw new NullPointerException("null diagram"); //$NON-NLS-1$ if (substitutions == null) throw new NullPointerException("null substitutions"); //$NON-NLS-1$ this.element = element; this.canvas = canvas; this.diagram = diagram; this.substitutions = substitutions; } @Override public void dispose() { canvas = null; diagram = null; } @Override public void execute(MonitorVariableValue result) { // Implement some kind of throttling for AWT thread element // update scheduling to keep the amount of AWT scheduling // down to a minimum. if (inUpdate == null) inUpdate = new AtomicBoolean(false); if (lastScheduledUpdate == null) lastScheduledUpdate = new AtomicReference(); lastScheduledUpdate.set(result); // Don't schedule update if there was already one in the pipe. synchronized (inUpdate) { if (!inUpdate.compareAndSet(false, true)) return; } //System.out.println(this + ".execute(" + result + "+")"); scheduleUpdate(); } @Override public void run() { if (isDisposed()) return; IElement el = ElementUtils.getByData(diagram, element); if (el == null) return; try { performUpdate(el); } finally { // Mark null to allow new update scheduling to commence. synchronized (inUpdate) { if (lastScheduledUpdate.get() != null) scheduleUpdate(); else inUpdate.set(false); } } } private void scheduleUpdate() { ICanvasContext canvas = this.canvas; if (!isDisposed()) ThreadUtils.asyncExec(canvas.getThreadAccess(), this); } private void performUpdate(IElement el) { // Get the last updated monitor value but don't yet // mark the container null to keep the outer code // from scheduling new updates until this one is // finished. MonitorVariableValue result = lastScheduledUpdate.getAndSet(null); String value = ""; //$NON-NLS-1$ if (result != null) { if (result.getValue() != null) { value = result.getValue();//ValueFormatUtil.valueStr(result.getValue(), format); } else { value = ""; //$NON-NLS-1$ } el.setHint(MonitorClass.KEY_MONITOR_COMPONENT, result.getMonitorVariable().getMonitorComponent()); ElementUtils.setOrRemoveHint(el, MonitorClass.KEY_MONITOR_IS_EXTERNAL, result.getMonitorVariable().isExternal()); } else { el.removeHint(MonitorClass.KEY_MONITOR_COMPONENT); el.removeHint(MonitorClass.KEY_MONITOR_IS_EXTERNAL); } substitutions.put("#v1", value); //$NON-NLS-1$ final Map subs = el.getHint(MonitorClass.KEY_MONITOR_SUBSTITUTIONS); if (substitutions != subs) el.setHint(MonitorClass.KEY_MONITOR_SUBSTITUTIONS, substitutions); //System.out.println("REPLACING #v1: " + substitutions.get("#v1")); el.setHint(Hints.KEY_DIRTY, Hints.VALUE_SG_DELAYED_UPDATE); } @Override public void exception(Throwable t) { ErrorLogger.defaultLogError(t); } @Override public boolean isDisposed() { return canvas == null || diagram == null || canvas.isDisposed(); } @Override public int hashCode() { return element.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; MonitorListener other = (MonitorListener) obj; return element.equals(other.element); } }