--- /dev/null
+/*******************************************************************************\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.modeling.ui.diagram.monitor;\r
+\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.Rectangle2D;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+import java.util.concurrent.atomic.AtomicReference;\r
+\r
+import org.simantics.browsing.ui.common.ErrorLogger;\r
+import org.simantics.common.color.Color;\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.db.AsyncReadGraph;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.util.EvaluatingListener;\r
+import org.simantics.db.layer0.util.EvaluatingListener.Evaluation;\r
+import org.simantics.db.layer0.variable.RVI;\r
+import org.simantics.db.layer0.variable.Variables;\r
+import org.simantics.db.procedure.AsyncProcedure;\r
+import org.simantics.diagram.adapter.SyncElementFactory;\r
+import org.simantics.diagram.content.ConnectionUtil;\r
+import org.simantics.diagram.elements.MonitorClass;\r
+import org.simantics.diagram.stubs.DiagramResource;\r
+import org.simantics.diagram.stubs.G2DResource;\r
+import org.simantics.diagram.synchronization.CompositeHintSynchronizer;\r
+import org.simantics.diagram.synchronization.IHintSynchronizer;\r
+import org.simantics.diagram.synchronization.SynchronizationHints;\r
+import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;\r
+import org.simantics.diagram.synchronization.graph.ElementLoader;\r
+import org.simantics.diagram.synchronization.graph.MonitorSynchronizer;\r
+import org.simantics.diagram.synchronization.graph.TransformSynchronizer;\r
+import org.simantics.diagram.ui.DiagramModelHints;\r
+import org.simantics.g2d.canvas.ICanvasContext;\r
+import org.simantics.g2d.diagram.IDiagram;\r
+import org.simantics.g2d.diagram.handler.DataElementMap;\r
+import org.simantics.g2d.diagram.handler.Relationship;\r
+import org.simantics.g2d.diagram.handler.RelationshipHandler;\r
+import org.simantics.g2d.element.ElementClass;\r
+import org.simantics.g2d.element.ElementHints;\r
+import org.simantics.g2d.element.ElementUtils;\r
+import org.simantics.g2d.element.IElement;\r
+import org.simantics.g2d.element.handler.TextEditor;\r
+import org.simantics.g2d.element.handler.impl.StaticObjectAdapter;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.modeling.ModelingResources;\r
+import org.simantics.scl.runtime.function.Function1;\r
+import org.simantics.ui.colors.Colors;\r
+import org.simantics.ui.fonts.FontDescriptor;\r
+import org.simantics.ui.fonts.Fonts;\r
+import org.simantics.utils.datastructures.Callback;\r
+import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
+import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;\r
+\r
+/**\r
+ * TODO: recognize experiment disposal and reset monitor contents at that point\r
+ * FIXME: monitor does not handle editing properly, and tries to include physical unit as part of numeric value\r
+ */\r
+public class MonitorClassFactory2 extends SyncElementFactory {\r
+\r
+ private static final Key KEY_VARIABLE_LISTENER = new KeyOf(MonitorListener.class,\r
+ "MONITOR_VARIABLE_LISTENER");\r
+\r
+ private static final String CLASS_ID = "Monitor";\r
+\r
+ private static final IHintSynchronizer HINT_SYNCHRONIZER = new CompositeHintSynchronizer(\r
+ MonitorSynchronizer.INSTANCE,\r
+ TransformSynchronizer.INSTANCE);\r
+\r
+ public static ElementClass createMonitorClass(Resource elementType) {\r
+ // set "default scale" to no scaling, 1.0, 1.0\r
+ return MonitorClass.create(1.0, 1.0, new StaticObjectAdapter(elementType)).setId(CLASS_ID);\r
+ }\r
+\r
+ // staticScale{X,Y} define the scale of the static monitor image\r
+ public static ElementClass createMonitorClass(Resource elementType, IElement parentElement, HashMap<String, String> substitutions, Object component, String suffix, double staticScaleX, double staticScaleY) {\r
+ return MonitorClass.create(parentElement, substitutions, component, suffix, staticScaleX, staticScaleY, new StaticObjectAdapter(elementType)).setId(CLASS_ID);\r
+ }\r
+\r
+ @Override\r
+ public void create(AsyncReadGraph graph, ICanvasContext canvas, IDiagram diagram, Resource elementType,\r
+ AsyncProcedure<ElementClass> procedure) {\r
+ procedure.execute(graph, createMonitorClass(elementType));\r
+ }\r
+\r
+ @Override\r
+ public void load(ReadGraph graph, final ICanvasContext canvas, final IDiagram diagram, final Resource element, final IElement e) throws DatabaseException {\r
+ if (!graph.hasStatement(element))\r
+ return;\r
+\r
+ final Layer0 L0 = Layer0.getInstance(graph);\r
+ final G2DResource G2D = G2DResource.getInstance(graph);\r
+ final DiagramResource DIA = DiagramResource.getInstance(graph);\r
+\r
+ // Must be done here to allow for the relationship manager to work properly.\r
+ e.setHint(ElementHints.KEY_OBJECT, element);\r
+ e.setHint(SynchronizationHints.HINT_SYNCHRONIZER, HINT_SYNCHRONIZER);\r
+\r
+ AffineTransform at = DiagramGraphUtil.getAffineTransform(graph, element);\r
+ ElementUtils.setTransform(e, at);\r
+\r
+ // Load alignments\r
+ Resource hAlign = graph.getPossibleObject(element, G2D.HasHorizontalAlignment);\r
+ Resource vAlign = graph.getPossibleObject(element, G2D.HasVerticalAlignment);\r
+\r
+ final Double borderWidth = graph.getPossibleRelatedValue(element, G2D.HasStrokeWidth);\r
+ Double direction = graph.getPossibleRelatedValue(element, DIA.HasDirection);\r
+ double bounds[] = DiagramGraphUtil.getPossibleRelatedDoubleArray(graph, element, G2D.HasBounds);\r
+ if (bounds != null) {\r
+ e.setHint(ElementHints.KEY_BOUNDS, new Rectangle2D.Double(bounds[0], bounds[1], bounds[2], bounds[3]));\r
+ }\r
+\r
+ if (hAlign != null)\r
+ e.setHint(ElementHints.KEY_HORIZONTAL_ALIGN, DiagramGraphUtil.toAlignment(hAlign, G2D, MonitorClass.DEFAULT_HORIZONTAL_ALIGN));\r
+ if (vAlign != null)\r
+ e.setHint(ElementHints.KEY_VERTICAL_ALIGN, DiagramGraphUtil.toVerticalAlignment(vAlign, G2D, MonitorClass.DEFAULT_VERTICAL_ALIGN));\r
+ if (direction != null)\r
+ e.setHint(MonitorClass.KEY_DIRECTION, direction);\r
+ if (borderWidth != null)\r
+ e.setHint(MonitorClass.KEY_BORDER_WIDTH, borderWidth);\r
+\r
+ String suffix = graph.getPossibleRelatedValue(element, DIA.HasMonitorSuffix, Bindings.STRING);\r
+ if (suffix != null) e.setHint(MonitorClass.KEY_MONITOR_SUFFIX, suffix);\r
+\r
+ String label = graph.getPossibleRelatedValue(element, L0.HasLabel);\r
+ ElementUtils.setText(e, label);\r
+\r
+ FontDescriptor fd = graph.getPossibleRelatedAdapter(element, DIA.HasFont, FontDescriptor.class);\r
+ if(fd != null) ElementUtils.setTextFont(e, Fonts.awt(fd));\r
+ Color color = graph.getPossibleRelatedAdapter(element, DIA.HasColor, Color.class);\r
+ if(color != null) ElementUtils.setTextColor(e, Colors.awt(color));\r
+\r
+ loadParentRelationships(graph, element, e);\r
+\r
+ final Map<String, String> substitutions = new HashMap<String, String>();\r
+ substitutions.put("#v1", "");\r
+\r
+ final Resource diagramRuntime = diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RUNTIME_RESOURCE);\r
+ if (diagramRuntime != null) {\r
+ final Session session = graph.getSession();\r
+\r
+ // Resolve validator for monitor input if possible.\r
+ final AtomicReference<Function1<String, String>> validator = new AtomicReference<Function1<String, String>>();\r
+ MonitorVariable monitorVariable = graph.syncRequest(new ResolveMonitorVariable(diagramRuntime, element));\r
+ boolean readOnly = true;\r
+ if (monitorVariable != null) {\r
+ Function1<String, String> func = monitorVariable.getVariable().getPossiblePropertyValue(graph, Variables.INPUT_VALIDATOR); \r
+ validator.set( func );\r
+ if (func != null)\r
+ e.setHint(MonitorClass.KEY_INPUT_VALIDATOR, func);\r
+ RVI rvi = monitorVariable.getRVI();\r
+ if (rvi != null)\r
+ e.setHint(MonitorClass.KEY_RVI, rvi);\r
+ readOnly = Boolean.TRUE.equals(\r
+ monitorVariable.getVariable().getPossiblePropertyValue(graph, Variables.READONLY, Bindings.BOOLEAN));\r
+ }\r
+\r
+ TextEditor ed = null;\r
+ if (!readOnly &&\r
+ (ed = e.getElementClass().getAtMostOneItemOfClass(TextEditor.class)) != null) {\r
+ ed.setModifier(e, new TextEditor.Modifier() {\r
+ @Override\r
+ public String getValue(IElement e) {\r
+ return MonitorClass.editText(e);\r
+ }\r
+\r
+ @Override\r
+ public String isValid(IElement e, String text) {\r
+ if (validator.get() != null)\r
+ return validator.get().apply(text);\r
+ return null;\r
+ }\r
+\r
+ @Override\r
+ public void modify(final IElement e, final String text) {\r
+ session.asyncRequest(new ResolveMonitorVariable(diagramRuntime, element),\r
+ new EvaluatingListener<MonitorVariable>(\r
+ new EvaluatingListener.Criterion<MonitorVariable>() {\r
+ @Override\r
+ public Evaluation evaluate(MonitorVariable result) {\r
+ return result != null ? Evaluation.ACCEPT : Evaluation.IGNORE;\r
+ }\r
+ }) {\r
+ @Override\r
+ public void accepted(MonitorVariable var) {\r
+ session.asyncRequest(new MonitorVariableWrite(var.getVariable(), text), new Callback<DatabaseException>() {\r
+ @Override\r
+ public void run(DatabaseException e) {\r
+ if (e != null)\r
+ ErrorLogger.defaultLogError(e);\r
+ }\r
+ });\r
+ }\r
+ @Override\r
+ public void exception(Throwable t) {\r
+ ErrorLogger.defaultLogError(t);\r
+ }\r
+ });\r
+ }\r
+\r
+ });\r
+ }\r
+\r
+ IElement mappedElement = diagram.getDiagramClass().getSingleItem(DataElementMap.class).getElement(diagram, element);\r
+ MonitorListener monitorListener = new MonitorListener(element, canvas, diagram, substitutions);\r
+ if (mappedElement != null) {\r
+ MonitorListener oldListener = mappedElement.getHint(KEY_VARIABLE_LISTENER);\r
+ if (oldListener != null)\r
+ oldListener.dispose();\r
+ mappedElement.setHint(KEY_VARIABLE_LISTENER, monitorListener);\r
+ }\r
+\r
+ if(monitorVariable != null)\r
+ graph.asyncRequest(new MonitorVariableValueRequest(diagramRuntime, element), monitorListener);\r
+ \r
+ }\r
+ }\r
+\r
+ private void loadParentRelationships(ReadGraph graph, Resource element, IElement e) throws DatabaseException {\r
+ DiagramResource DIA = DiagramResource.getInstance(graph);\r
+ ModelingResources MOD = ModelingResources.getInstance(graph);\r
+\r
+ Resource monitorComponent = graph.getPossibleObject(element, DIA.HasMonitorComponent);\r
+ Resource parentDiagramElement = null;\r
+ if (monitorComponent != null)\r
+ parentDiagramElement = graph.getPossibleObject(monitorComponent, MOD.ComponentToElement);\r
+\r
+ // Load parent relationship after all elements have been loaded.\r
+ if (parentDiagramElement != null) {\r
+ final Resource pde = parentDiagramElement;\r
+ e.setHint(DiagramModelHints.KEY_ELEMENT_LOADER, new ElementLoader() {\r
+ @Override\r
+ public void load(ReadGraph g, IDiagram diagram, IElement element) throws DatabaseException {\r
+ loadParentRelationship(g, diagram, element, pde);\r
+ }\r
+ });\r
+ }\r
+ }\r
+\r
+ boolean loadParentRelationship(ReadGraph g, IDiagram diagram, IElement element, Resource parentElementResource)\r
+ throws DatabaseException {\r
+ // If no relationship handler is available, stop loading.\r
+ RelationshipHandler rh = diagram.getDiagramClass().getAtMostOneItemOfClass(RelationshipHandler.class);\r
+ if (rh == null)\r
+ return true;\r
+\r
+ DiagramResource DIA = DiagramResource.getInstance(g);\r
+ DataElementMap map = diagram.getDiagramClass().getSingleItem(DataElementMap.class);\r
+ IElement parentElement = map.getElement(diagram, parentElementResource);\r
+\r
+ if (parentElement != null) {\r
+ element.setHint(ElementHints.KEY_PARENT_ELEMENT, parentElement);\r
+ rh.claim(diagram, element, Relationship.CHILD_OF, parentElement);\r
+\r
+ Resource tailNode = null;\r
+ if (g.isInstanceOf(parentElementResource, DIA.Connection)) {\r
+ tailNode = ConnectionUtil.getConnectionTailNode(g, parentElementResource);\r
+ }\r
+\r
+ if (tailNode != null) {\r
+ IElement tailNodeElement = map.getElement(diagram, tailNode);\r
+ if (parentElement != null) {\r
+ element.setHint(ElementHints.KEY_PARENT_ELEMENT, tailNodeElement);\r
+ rh.claim(diagram, element, Relationship.CHILD_OF, tailNodeElement);\r
+ }\r
+ }\r
+\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ }\r
+\r
+}
\ No newline at end of file