-package org.simantics.diagram.profile;\r
-\r
-import java.awt.Color;\r
-import java.awt.Font;\r
-import java.awt.geom.AffineTransform;\r
-import java.awt.geom.Point2D;\r
-import java.awt.geom.Rectangle2D;\r
-\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.datatypes.literal.Vec2d;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.layer0.variable.RVI;\r
-import org.simantics.db.layer0.variable.Variable;\r
-import org.simantics.diagram.elements.ITextListener;\r
-import org.simantics.diagram.elements.TextGridNode;\r
-import org.simantics.diagram.elements.TextNode;\r
-import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;\r
-import org.simantics.g2d.utils.Alignment;\r
-import org.simantics.modeling.ModelingResources;\r
-import org.simantics.scenegraph.INode;\r
-import org.simantics.scenegraph.g2d.nodes.ConnectionNode;\r
-import org.simantics.scenegraph.profile.EvaluationContext;\r
-import org.simantics.scenegraph.profile.common.ProfileVariables;\r
-import org.simantics.scenegraph.utils.GeometryUtils;\r
-import org.simantics.scenegraph.utils.NodeUtil;\r
-import org.simantics.scl.runtime.function.Function1;\r
-import org.simantics.ui.colors.Colors;\r
-\r
-/**\r
- * @author Antti Villberg\r
- * @author Tuukka Lehtonen\r
- */\r
-public abstract class TextGridStyle extends StyleBase<MonitorTextGridResult> {\r
-\r
- private final Font FONT = Font.decode("Arial 12");\r
- private final Color BACKGROUND_COLOR = new Color(255, 255, 255, 192);\r
- private static final Rectangle2D EMPTY_BOUNDS = new Rectangle2D.Double(0, 0, 0, 0);\r
-\r
- // NOTE: this is a hack\r
- String id;\r
-\r
- protected double xOffset;\r
- protected double yOffset;\r
-\r
- public TextGridStyle() {\r
- this(0.0, 2.1);\r
- }\r
-\r
- public TextGridStyle(double xOffset, double yOffset) {\r
- this.xOffset = xOffset;\r
- this.yOffset = yOffset;\r
- }\r
-\r
- public Resource getPropertyRelation(ReadGraph g, Resource module) {\r
- throw new Error("Fix this");\r
- }\r
-\r
- /**\r
- * @return the name of the scene graph node to create to represent the text\r
- * element created by this style\r
- */\r
- public String getNodeName() {\r
- return getClass().getSimpleName();\r
- }\r
-\r
- /**\r
- * Override to customize.\r
- * \r
- * @param graph\r
- * @param element\r
- * @return\r
- * @throws DatabaseException\r
- */\r
- protected Resource getConfigurationComponent(ReadGraph graph, Resource element) throws DatabaseException {\r
- ModelingResources mr = ModelingResources.getInstance(graph);\r
- Resource config = graph.getPossibleObject(element, mr.ElementToComponent);\r
- return config;\r
- }\r
-\r
- /**\r
- * Override to customize.\r
- * \r
- * @param graph\r
- * @param element\r
- * @return\r
- * @throws DatabaseException\r
- */\r
- protected String getConfigurationComponentNameForElement(ReadGraph graph, Resource element) throws DatabaseException {\r
- Resource config = getConfigurationComponent(graph, element);\r
- if (config == null)\r
- return null;\r
- String name = graph.getPossibleRelatedValue(config, getPropertyRelation(graph,element), Bindings.STRING);\r
- return name;\r
- }\r
- \r
- public AffineTransform getTransform(INode node, AffineTransform parentTransform, Rectangle2D elementBounds, int location, boolean up) {\r
- return getTransform(parentTransform, elementBounds, location, up);\r
- }\r
-\r
- public AffineTransform getTransform(AffineTransform parentTransform, Rectangle2D elementBounds, int location, boolean up) {\r
-\r
- double scale = GeometryUtils.getScale(parentTransform);\r
-\r
- AffineTransform at = AffineTransform.getTranslateInstance(\r
- parentTransform.getTranslateX() + elementBounds.getCenterX() * scale + xOffset,\r
- parentTransform.getTranslateY() + elementBounds.getMinY() * scale + yOffset*(location-1) + (up ? 0.0 : (2.0*yOffset) + elementBounds.getHeight() * scale) \r
- );\r
- at.scale(0.15, 0.15);\r
-\r
- return at;\r
- \r
- }\r
-\r
- protected String rowId() {\r
- return "";\r
- }\r
-\r
- @Override\r
- public MonitorTextGridResult calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration)\r
- throws DatabaseException {\r
- String name = getConfigurationComponentNameForElement(graph, element);\r
- if (name == null)\r
- return null;\r
- AffineTransform transform = DiagramGraphUtil.getDynamicAffineTransform(graph, runtimeDiagram, element);\r
- Vec2d offset = DiagramGraphUtil.getOffset(graph, element);\r
- boolean enabled = !DiagramGraphUtil.getProfileMonitorsHidden(graph, element);\r
- boolean up = DiagramGraphUtil.getProfileMonitorsUp(graph, element);\r
- double spacing = DiagramGraphUtil.getProfileMonitorSpacing(graph, element);\r
- return new MonitorTextGridResult(rowId(), name, "", "", enabled, up, spacing, null, null, null, transform, offset);\r
- }\r
-\r
- // Not to be modified\r
- protected final static Point2D[] DEFAULT_CELL_OFFSETS = new Point2D[] {\r
- new Point2D.Double(-45, 0),\r
- new Point2D.Double(22, 0),\r
- new Point2D.Double(24, 0)\r
- };\r
-\r
- // Not to be modified\r
- protected final static Point2D[] ZERO_CELL_OFFSETS = new Point2D[] {\r
- new Point2D.Double(0, 0),\r
- new Point2D.Double(0, 0),\r
- new Point2D.Double(0, 0)\r
- };\r
-\r
- protected Point2D[] getCellOffsets() {\r
- return DEFAULT_CELL_OFFSETS;\r
- }\r
-\r
- @Override\r
- public void applyStyleForNode(EvaluationContext observer, INode _node, MonitorTextGridResult result) {\r
-\r
- String value = result != null ? result.getText1() : null;\r
- boolean enabled = result != null ? result.getEnabled() : false;\r
-\r
- if (value != null && enabled) {\r
-\r
- // if (value != null && !value.isEmpty() && !value.trim().isEmpty()) {\r
-\r
- String value2 = result != null ? result.getText2() : null;\r
- String value3 = result != null ? result.getText3() : null;\r
- \r
- double spacing = result.getSpacing();\r
-\r
- final Function1<String, String> modifier = result != null ? result.getModifier() : null;\r
- final Function1<String, String> validator = result != null ? result.getValidator() : null;\r
- final Function1<Vec2d, Boolean> translator = result != null ? result.getTranslator() : null;\r
- final RVI rvi = result != null ? result.getRVI() : null;\r
-\r
- final TextGridNode node = ProfileVariables.claimChild(_node, "", "TextGridStyle", TextGridNode.class, observer);\r
- if (node == null)\r
- return;\r
-\r
- // This assumes that this TextGridStyle instance will be devoted to\r
- // this row ID until the end of its life.\r
- String id = result.getRowId();\r
- //System.out.println(this + " ID: " + id);\r
- if (!id.equals(this.id)) {\r
- //System.out.println(this + " SET ID: " + this.id + " -> " + id);\r
- this.id = id;\r
- }\r
-\r
- Integer newRow = observer.getTemporaryProperty(_node, "location");\r
- if (newRow == null)\r
- newRow = 1;\r
-\r
- // Remove from existing row to add to another row if necessary.\r
- Integer row = observer.getProperty(_node, id);\r
- if (row != null && row != newRow) {\r
- String actualId = node.getRowId(row);\r
- if (id.equals(actualId)) {\r
- node.removeRow(row);\r
- }\r
- }\r
- row = newRow;\r
-\r
- node.setRowId(row, id);\r
- observer.setProperty(_node, id, row);\r
- observer.setTemporaryProperty(_node, "location", row + 1);\r
-\r
- node.setText(2, row, value2);\r
- node.setUp(result.getUp());\r
-\r
- MonitorTextGridResult cache = node.getCache(1, row);\r
- if(cache != null && cache.sameStructure(result)) return;\r
-\r
- node.setCache(1, row, result);\r
-\r
- boolean isConnection = _node instanceof ConnectionNode;\r
- \r
- Rectangle2D elementBounds = isConnection ? EMPTY_BOUNDS : NodeUtil.getLocalElementBounds(_node);\r
- if(elementBounds == null) {\r
- new Exception("Cannot get local element bounds for node " + _node.toString()).printStackTrace();\r
- // This is here for checking why getLocalElementBounds failed in the debugger.\r
- NodeUtil.getLocalElementBounds(_node);\r
- return;\r
- }\r
-\r
- // System.err.println("elementBounds " + elementBounds);\r
- // System.err.println("parentTransform " + result.getParentTransform());\r
-\r
- AffineTransform at = getTransform(_node,result.getParentTransform(), elementBounds, row, result.getUp());\r
- Vec2d offset = result.getOffset();\r
-\r
- Point2D[] cellOffsets = getCellOffsets();\r
- \r
- AffineTransform at1 = new AffineTransform(at);\r
- at1.translate(cellOffsets[0].getX(),cellOffsets[0].getY());\r
- AffineTransform at2 = new AffineTransform(at);\r
- at2.translate(cellOffsets[1].getX()+spacing,cellOffsets[1].getY());\r
- AffineTransform at3 = new AffineTransform(at);\r
- at3.translate(cellOffsets[2].getX()+spacing,cellOffsets[2].getY());\r
- \r
- at1.translate(offset.x, offset.y);\r
- at2.translate(offset.x, offset.y);\r
- at3.translate(offset.x, offset.y);\r
-\r
- node.setTransform(1, row, at1);\r
- node.setTransform(2, row, at2);\r
- node.setTransform(3, row, at3);\r
-\r
- Alignment[] alignments = result.getAlignments();\r
- if(alignments != null) {\r
- node.setHorizontalAlignment(1, row, (byte) alignments[0].ordinal());\r
- node.setHorizontalAlignment(2, row, (byte) alignments[1].ordinal());\r
- node.setHorizontalAlignment(3, row, (byte) alignments[2].ordinal());\r
- } else {\r
- node.setHorizontalAlignment(1, row, (byte) getAlignment(1).ordinal());\r
- node.setHorizontalAlignment(2, row, (byte) getAlignment(2).ordinal());\r
- node.setHorizontalAlignment(3, row, (byte) getAlignment(3).ordinal());\r
- }\r
- \r
- Alignment[] verticalAlignments = result.getVerticalAlignments();\r
- if(verticalAlignments != null) {\r
- node.setVerticalAlignment(1, row, (byte) verticalAlignments[0].ordinal());\r
- node.setVerticalAlignment(2, row, (byte) verticalAlignments[1].ordinal());\r
- node.setVerticalAlignment(3, row, (byte) verticalAlignments[2].ordinal());\r
- } else {\r
- node.setVerticalAlignment(1, row, (byte) getVerticalAlignment(1).ordinal());\r
- node.setVerticalAlignment(2, row, (byte) getVerticalAlignment(2).ordinal());\r
- node.setVerticalAlignment(3, row, (byte) getVerticalAlignment(3).ordinal());\r
- }\r
-\r
- node.setZIndex(3000);\r
-\r
- org.simantics.common.color.Color color = result.getColor();\r
- java.awt.Color awtColor = color != null ? Colors.awt(color) : Color.DARK_GRAY;\r
-\r
- setTextNodeData(node, 1, row, value, FONT, awtColor, BACKGROUND_COLOR);\r
- setTextNodeData(node, 2, row, value2, result.getPending(), FONT, awtColor, BACKGROUND_COLOR);\r
- setTextNodeData(node, 3, row, value3, FONT, awtColor, BACKGROUND_COLOR);\r
-\r
- node.setEditable(1, row, false);\r
- node.setForceEventListening(2, row, true);\r
- node.setEditable(2, row, modifier != null);\r
- node.setEditable(3, row, false);\r
-\r
- final int finalRow = row;\r
-\r
- if (modifier != null) {\r
- node.setTextListener(2, row, new ITextListener() {\r
- @Override\r
- public void textChanged() {}\r
-\r
- @Override\r
- public void textEditingStarted() {}\r
-\r
- @Override\r
- public void textEditingCancelled() {\r
- }\r
-\r
- @Override\r
- public void textEditingEnded() {\r
-\r
- TextNode t = node.get(2, finalRow);\r
- if (t == null)\r
- return;\r
-\r
- if(!t.getText().equals(t.getTextBeforeEdit()))\r
- modifier.apply(t.getText());\r
-\r
- }\r
- });\r
- } else {\r
- node.setTextListener(2, row, null);\r
- }\r
-\r
- node.setInputValidator(2, row, validator);\r
- node.setTranslator(translator);\r
- \r
- node.setRVI(2, row, rvi);\r
-\r
- postProcessNode(node, row);\r
-\r
- } else {\r
- cleanupStyleForNode(observer, _node);\r
- }\r
- }\r
-\r
- private void setTextNodeData(TextGridNode node, int x, int y, String text, Font font, Color fgColor, Color bgColor) {\r
- if (text != null) {\r
- node.setText(x, y, text);\r
- node.setFont(x, y, font);\r
- node.setColor(x, y, fgColor);\r
- node.setBackgroundColor(x, y, bgColor);\r
- } else {\r
- // Prevent rendering of the node.\r
- node.setFont(x, y, null);\r
- }\r
- }\r
-\r
- private void setTextNodeData(TextGridNode node, int x, int y, String text, boolean pending, Font font, Color fgColor, Color bgColor) {\r
- setTextNodeData(node, x, y, text, font, fgColor, bgColor);\r
- node.setPending(x, y, pending);\r
- }\r
-\r
- protected Alignment getAlignment(int column) {\r
- switch(column) {\r
- case 1: return Alignment.TRAILING;\r
- case 2: return Alignment.TRAILING;\r
- case 3: return Alignment.LEADING;\r
- default: return Alignment.LEADING;\r
- }\r
- }\r
-\r
- protected Alignment getVerticalAlignment(int column) {\r
- return Alignment.TRAILING;\r
- }\r
-\r
- @Override\r
- protected void cleanupStyleForNode(EvaluationContext observer, INode _node) {\r
- Integer row = observer.getProperty(_node, id);\r
- //System.out.println(this + " cleanup(" + id + ", " + row + ")");\r
- //System.out.println(element);\r
- if (row == null)\r
- return;\r
- observer.setProperty(_node, id, null);\r
- TextGridNode node = ProfileVariables.browseChild(_node, "TextGridStyle");\r
- if (node != null)\r
- node.removeRow(row);\r
- }\r
-\r
- protected void postProcessNode(TextGridNode node, int row) {\r
- }\r
-\r
-}\r
+package org.simantics.diagram.profile;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.datatypes.literal.Vec2d;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.variable.RVI;
+import org.simantics.db.layer0.variable.Variable;
+import org.simantics.diagram.elements.ITextListener;
+import org.simantics.diagram.elements.TextGridNode;
+import org.simantics.diagram.elements.TextNode;
+import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;
+import org.simantics.g2d.utils.Alignment;
+import org.simantics.modeling.ModelingResources;
+import org.simantics.scenegraph.INode;
+import org.simantics.scenegraph.g2d.nodes.ConnectionNode;
+import org.simantics.scenegraph.profile.EvaluationContext;
+import org.simantics.scenegraph.profile.common.ProfileVariables;
+import org.simantics.scenegraph.utils.GeometryUtils;
+import org.simantics.scenegraph.utils.NodeUtil;
+import org.simantics.scl.runtime.function.Function1;
+import org.simantics.ui.colors.Colors;
+import org.simantics.utils.datastructures.Pair;
+
+/**
+ * @author Antti Villberg
+ * @author Tuukka Lehtonen
+ */
+public abstract class TextGridStyle extends StyleBase<MonitorTextGridResult> {
+
+ private final Font FONT = Font.decode("Arial 12");
+ private final Color BACKGROUND_COLOR = new Color(255, 255, 255, 192);
+ private static final Rectangle2D EMPTY_BOUNDS = new Rectangle2D.Double(0, 0, 0, 0);
+
+ protected double xOffset;
+ protected double yOffset;
+
+ public TextGridStyle(Resource r) {
+ this(r, 0.0, 2.1);
+ }
+
+ public TextGridStyle(Resource r, double xOffset, double yOffset) {
+ super(r);
+ this.xOffset = xOffset;
+ this.yOffset = yOffset;
+ }
+
+ public Resource getPropertyRelation(ReadGraph g, Resource module) {
+ throw new Error("Fix this");
+ }
+
+ /**
+ * @return the name of the scene graph node to create to represent the text
+ * element created by this style
+ */
+ public String getNodeName() {
+ return getClass().getSimpleName();
+ }
+
+ /**
+ * Override to customize.
+ *
+ * @param graph
+ * @param element
+ * @return
+ * @throws DatabaseException
+ */
+ protected Resource getConfigurationComponent(ReadGraph graph, Resource element) throws DatabaseException {
+ ModelingResources mr = ModelingResources.getInstance(graph);
+ Resource config = graph.getPossibleObject(element, mr.ElementToComponent);
+ return config;
+ }
+
+ /**
+ * Override to customize.
+ *
+ * @param graph
+ * @param element
+ * @return
+ * @throws DatabaseException
+ */
+ protected String getConfigurationComponentNameForElement(ReadGraph graph, Resource element) throws DatabaseException {
+ Resource config = getConfigurationComponent(graph, element);
+ if (config == null)
+ return null;
+ String name = graph.getPossibleRelatedValue(config, getPropertyRelation(graph,element), Bindings.STRING);
+ return name;
+ }
+
+ public AffineTransform getTransform(INode node, AffineTransform parentTransform, Rectangle2D elementBounds, int location, boolean up) {
+ return getTransform(parentTransform, elementBounds, location, up);
+ }
+
+ public AffineTransform getTransform(AffineTransform parentTransform, Rectangle2D elementBounds, int location, boolean up) {
+
+ double scale = GeometryUtils.getScale(parentTransform);
+
+ AffineTransform at = AffineTransform.getTranslateInstance(
+ parentTransform.getTranslateX() + elementBounds.getCenterX() * scale + xOffset,
+ parentTransform.getTranslateY() + elementBounds.getMinY() * scale + yOffset*(location-1) + (up ? 0.0 : (2.0*yOffset) + elementBounds.getHeight() * scale)
+ );
+ at.scale(0.15, 0.15);
+
+ return at;
+
+ }
+
+ protected String rowId() {
+ return "";
+ }
+
+ @Override
+ public MonitorTextGridResult calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration)
+ throws DatabaseException {
+ String name = getConfigurationComponentNameForElement(graph, element);
+ if (name == null)
+ return null;
+ AffineTransform transform = DiagramGraphUtil.getDynamicAffineTransform(graph, runtimeDiagram, element);
+ Vec2d offset = DiagramGraphUtil.getOffset(graph, element);
+ boolean enabled = !DiagramGraphUtil.getProfileMonitorsHidden(graph, element);
+ boolean up = DiagramGraphUtil.getProfileMonitorsUp(graph, element);
+ double spacing = DiagramGraphUtil.getProfileMonitorSpacing(graph, element);
+ return new MonitorTextGridResult(rowId(), name, "", "", enabled, up, spacing, null, null, null, transform, offset);
+ }
+
+ // Not to be modified
+ protected final static Point2D[] DEFAULT_CELL_OFFSETS = new Point2D[] {
+ new Point2D.Double(-45, 0),
+ new Point2D.Double(22, 0),
+ new Point2D.Double(24, 0)
+ };
+
+ // Not to be modified
+ protected final static Point2D[] ZERO_CELL_OFFSETS = new Point2D[] {
+ new Point2D.Double(0, 0),
+ new Point2D.Double(0, 0),
+ new Point2D.Double(0, 0)
+ };
+
+ protected Point2D[] getCellOffsets() {
+ return DEFAULT_CELL_OFFSETS;
+ }
+
+ @Override
+ public void applyStyleForNode(EvaluationContext observer, INode _node, MonitorTextGridResult result) {
+ String value = result != null ? result.getText1() : null;
+ boolean enabled = result != null ? result.getEnabled() : false;
+
+ if (value != null && enabled) {
+
+ Map<String, Pair<TextGridStyle, MonitorTextGridResult>> rows = observer.getProperty(_node, "rows");
+ if (rows == null) {
+ rows = new HashMap<String, Pair<TextGridStyle, MonitorTextGridResult>>();
+ observer.setProperty(_node, "rows", rows);
+ }
+ Pair<TextGridStyle, MonitorTextGridResult> oldResultPair = rows.get(result.getRowId());
+ if (oldResultPair != null && oldResultPair.first == this && oldResultPair.second.sameStructure(result)) {
+ return;
+ }
+
+ rows.put(rowIdKey(), new Pair<TextGridStyle, MonitorTextGridResult>(this, result));
+
+ // FIXME: Improve performance by calling refreshAll only once after all text grid style changes have been applied
+ refreshAll(observer, _node);
+ } else {
+ cleanupStyleForNode(observer, _node);
+ }
+ }
+
+ private static final Comparator<Pair<TextGridStyle, MonitorTextGridResult>> ROW_PRIORITY_COMPARATOR =
+ (o1, o2) -> Double.compare(o1.first.getPriority(), o2.first.getPriority());
+
+ private static void refreshAll(EvaluationContext observer, INode _node) {
+ final TextGridNode node = ProfileVariables.claimChild(_node, "", "TextGridStyle", TextGridNode.class, observer);
+ if (node == null)
+ return;
+
+ int row = 0;
+ Map<String, Pair<TextGridStyle, MonitorTextGridResult>> rows = observer.getProperty(_node, "rows");
+ if (rows != null) {
+ List<Pair<TextGridStyle, MonitorTextGridResult>> sortedRows = rows.values().stream()
+ .sorted(ROW_PRIORITY_COMPARATOR)
+ .collect(Collectors.toList());
+
+ for (Pair<TextGridStyle, MonitorTextGridResult> resultPair : sortedRows) {
+ row++;
+ TextGridStyle style = resultPair.first;
+ MonitorTextGridResult result = resultPair.second;
+
+ String value = result != null ? result.getText1() : null;
+ String value2 = result != null ? result.getText2() : null;
+ String value3 = result != null ? result.getText3() : null;
+
+ double spacing = result.getSpacing();
+
+ final Function1<String, String> modifier = result != null ? result.getModifier() : null;
+ final Function1<String, String> validator = result != null ? result.getValidator() : null;
+ final Function1<Vec2d, Boolean> translator = result != null ? result.getTranslator() : null;
+ final RVI rvi = result != null ? result.getRVI() : null;
+
+ node.setRowId(row, result.getRowId());
+
+ //setCurrentRowNumber(observer, _node, result.getRowId(), row);
+
+ //observer.setTemporaryProperty(_node, "location", row + 1);
+
+ node.setText(2, row, value2);
+ node.setUp(result.getUp());
+
+ //MonitorTextGridResult cache = node.getCache(1, row);
+ //if(cache != null && cache.sameStructure(result)) return;
+
+ node.setCache(1, row, result);
+
+ boolean isConnection = _node instanceof ConnectionNode;
+
+ Rectangle2D elementBounds = isConnection ? EMPTY_BOUNDS : NodeUtil.getLocalElementBounds(_node);
+ if (elementBounds == null) {
+ new Exception("Cannot get local element bounds for node " + _node.toString()).printStackTrace();
+ // This is here for checking why getLocalElementBounds failed in the debugger.
+ NodeUtil.getLocalElementBounds(_node);
+ return;
+ }
+
+ //System.err.println("elementBounds " + elementBounds);
+ //System.err.println("parentTransform " + result.getParentTransform());
+
+ AffineTransform at = style.getTransform(_node,result.getParentTransform(), elementBounds, row, result.getUp());
+ Vec2d offset = result.getOffset();
+
+ Point2D[] cellOffsets = style.getCellOffsets();
+
+ AffineTransform at1 = new AffineTransform(at);
+ at1.translate(cellOffsets[0].getX(),cellOffsets[0].getY());
+ AffineTransform at2 = new AffineTransform(at);
+ at2.translate(cellOffsets[1].getX()+spacing,cellOffsets[1].getY());
+ AffineTransform at3 = new AffineTransform(at);
+ at3.translate(cellOffsets[2].getX()+spacing,cellOffsets[2].getY());
+
+ at1.translate(offset.x, offset.y);
+ at2.translate(offset.x, offset.y);
+ at3.translate(offset.x, offset.y);
+
+ node.setTransform(1, row, at1);
+ node.setTransform(2, row, at2);
+ node.setTransform(3, row, at3);
+
+ Alignment[] alignments = result.getAlignments();
+ if(alignments != null) {
+ node.setHorizontalAlignment(1, row, (byte) alignments[0].ordinal());
+ node.setHorizontalAlignment(2, row, (byte) alignments[1].ordinal());
+ node.setHorizontalAlignment(3, row, (byte) alignments[2].ordinal());
+ } else {
+ node.setHorizontalAlignment(1, row, (byte) style.getAlignment(1).ordinal());
+ node.setHorizontalAlignment(2, row, (byte) style.getAlignment(2).ordinal());
+ node.setHorizontalAlignment(3, row, (byte) style.getAlignment(3).ordinal());
+ }
+
+ Alignment[] verticalAlignments = result.getVerticalAlignments();
+ if(verticalAlignments != null) {
+ node.setVerticalAlignment(1, row, (byte) verticalAlignments[0].ordinal());
+ node.setVerticalAlignment(2, row, (byte) verticalAlignments[1].ordinal());
+ node.setVerticalAlignment(3, row, (byte) verticalAlignments[2].ordinal());
+ } else {
+ node.setVerticalAlignment(1, row, (byte) style.getVerticalAlignment(1).ordinal());
+ node.setVerticalAlignment(2, row, (byte) style.getVerticalAlignment(2).ordinal());
+ node.setVerticalAlignment(3, row, (byte) style.getVerticalAlignment(3).ordinal());
+ }
+
+ node.setZIndex(3000);
+
+ org.simantics.common.color.Color color = result.getColor();
+ Color awtColor = color != null ? Colors.awt(color) : Color.DARK_GRAY;
+ Color bgColor = style.getBackgroundColor();
+ Font font = style.getFont();
+ style.setTextNodeData(node, 1, row, value, font, awtColor, bgColor);
+ style.setTextNodeData(node, 2, row, value2, result.getPending(), font, awtColor, bgColor);
+ style.setTextNodeData(node, 3, row, value3, font, awtColor, bgColor);
+
+ node.setEditable(1, row, false);
+ node.setForceEventListening(2, row, true);
+ node.setEditable(2, row, modifier != null);
+ node.setEditable(3, row, false);
+
+ final int finalRow = row;
+
+ if (modifier != null) {
+ node.setTextListener(2, row, new ITextListener() {
+ @Override
+ public void textChanged() {}
+
+ @Override
+ public void textEditingStarted() {}
+
+ @Override
+ public void textEditingCancelled() {
+ }
+
+ @Override
+ public void textEditingEnded() {
+
+ TextNode t = node.get(2, finalRow);
+ if (t == null)
+ return;
+
+ if(!t.getText().equals(t.getTextBeforeEdit()))
+ modifier.apply(t.getText());
+
+ }
+ });
+ } else {
+ node.setTextListener(2, row, null);
+ }
+
+ node.setInputValidator(2, row, validator);
+ node.setTranslator(translator);
+
+ node.setRVI(2, row, rvi);
+
+ style.postProcessNode(node, row);
+ }
+ }
+ // remove excess rows
+ int rowCount = node.computeRows();
+ while (row < rowCount) {
+ row++;
+ node.removeRow(row);
+ }
+ }
+
+ private void setTextNodeData(TextGridNode node, int x, int y, String text, Font font, Color fgColor, Color bgColor) {
+ if (text != null) {
+ node.setText(x, y, text);
+ node.setFont(x, y, font);
+ node.setColor(x, y, fgColor);
+ node.setBackgroundColor(x, y, bgColor);
+ } else {
+ // Prevent rendering of the node.
+ node.setFont(x, y, null);
+ }
+ }
+
+ private void setTextNodeData(TextGridNode node, int x, int y, String text, boolean pending, Font font, Color fgColor, Color bgColor) {
+ setTextNodeData(node, x, y, text, font, fgColor, bgColor);
+ node.setPending(x, y, pending);
+ }
+
+ protected Font getFont() {
+ return FONT;
+ }
+
+ protected Color getBackgroundColor() {
+ return BACKGROUND_COLOR;
+ }
+
+ protected Alignment getAlignment(int column) {
+ switch(column) {
+ case 1: return Alignment.TRAILING;
+ case 2: return Alignment.TRAILING;
+ case 3: return Alignment.LEADING;
+ default: return Alignment.LEADING;
+ }
+ }
+
+ protected Alignment getVerticalAlignment(int column) {
+ return Alignment.TRAILING;
+ }
+
+ @Override
+ protected void cleanupStyleForNode(EvaluationContext observer, INode _node) {
+ Map<String, Pair<Double, MonitorTextGridResult>> rows = observer.getProperty(_node, "rows");
+ if (rows != null) {
+ rows.remove(rowIdKey());
+ if (rows.isEmpty()) {
+ observer.setProperty(_node, "rows", null);
+ }
+ }
+ refreshAll(observer, _node);
+ }
+
+ protected void postProcessNode(TextGridNode node, int row) {
+ }
+
+ private String rowIdKey() {
+ return "style" + getIdentity().toString();
+ }
+
+}