1 package org.simantics.diagram.profile;
5 import java.awt.geom.AffineTransform;
6 import java.awt.geom.Point2D;
7 import java.awt.geom.Rectangle2D;
9 import org.simantics.databoard.Bindings;
10 import org.simantics.datatypes.literal.Vec2d;
11 import org.simantics.db.ReadGraph;
12 import org.simantics.db.Resource;
13 import org.simantics.db.exception.DatabaseException;
14 import org.simantics.db.layer0.variable.RVI;
15 import org.simantics.db.layer0.variable.Variable;
16 import org.simantics.diagram.elements.ITextListener;
17 import org.simantics.diagram.elements.TextGridNode;
18 import org.simantics.diagram.elements.TextNode;
19 import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;
20 import org.simantics.g2d.utils.Alignment;
21 import org.simantics.modeling.ModelingResources;
22 import org.simantics.scenegraph.INode;
23 import org.simantics.scenegraph.g2d.nodes.ConnectionNode;
24 import org.simantics.scenegraph.profile.EvaluationContext;
25 import org.simantics.scenegraph.profile.common.ProfileVariables;
26 import org.simantics.scenegraph.utils.GeometryUtils;
27 import org.simantics.scenegraph.utils.NodeUtil;
28 import org.simantics.scl.runtime.function.Function1;
29 import org.simantics.ui.colors.Colors;
32 * @author Antti Villberg
33 * @author Tuukka Lehtonen
35 public abstract class TextGridStyle extends StyleBase<MonitorTextGridResult> {
37 private final Font FONT = Font.decode("Arial 12");
38 private final Color BACKGROUND_COLOR = new Color(255, 255, 255, 192);
39 private static final Rectangle2D EMPTY_BOUNDS = new Rectangle2D.Double(0, 0, 0, 0);
41 // // NOTE: this is a hack
44 protected double xOffset;
45 protected double yOffset;
47 public TextGridStyle(Resource r) {
51 public TextGridStyle(Resource r, double xOffset, double yOffset) {
53 this.xOffset = xOffset;
54 this.yOffset = yOffset;
57 public Resource getPropertyRelation(ReadGraph g, Resource module) {
58 throw new Error("Fix this");
62 * @return the name of the scene graph node to create to represent the text
63 * element created by this style
65 public String getNodeName() {
66 return getClass().getSimpleName();
70 * Override to customize.
75 * @throws DatabaseException
77 protected Resource getConfigurationComponent(ReadGraph graph, Resource element) throws DatabaseException {
78 ModelingResources mr = ModelingResources.getInstance(graph);
79 Resource config = graph.getPossibleObject(element, mr.ElementToComponent);
84 * Override to customize.
89 * @throws DatabaseException
91 protected String getConfigurationComponentNameForElement(ReadGraph graph, Resource element) throws DatabaseException {
92 Resource config = getConfigurationComponent(graph, element);
95 String name = graph.getPossibleRelatedValue(config, getPropertyRelation(graph,element), Bindings.STRING);
99 public AffineTransform getTransform(INode node, AffineTransform parentTransform, Rectangle2D elementBounds, int location, boolean up) {
100 return getTransform(parentTransform, elementBounds, location, up);
103 public AffineTransform getTransform(AffineTransform parentTransform, Rectangle2D elementBounds, int location, boolean up) {
105 double scale = GeometryUtils.getScale(parentTransform);
107 AffineTransform at = AffineTransform.getTranslateInstance(
108 parentTransform.getTranslateX() + elementBounds.getCenterX() * scale + xOffset,
109 parentTransform.getTranslateY() + elementBounds.getMinY() * scale + yOffset*(location-1) + (up ? 0.0 : (2.0*yOffset) + elementBounds.getHeight() * scale)
111 at.scale(0.15, 0.15);
117 protected String rowId() {
122 public MonitorTextGridResult calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration)
123 throws DatabaseException {
124 String name = getConfigurationComponentNameForElement(graph, element);
127 AffineTransform transform = DiagramGraphUtil.getDynamicAffineTransform(graph, runtimeDiagram, element);
128 Vec2d offset = DiagramGraphUtil.getOffset(graph, element);
129 boolean enabled = !DiagramGraphUtil.getProfileMonitorsHidden(graph, element);
130 boolean up = DiagramGraphUtil.getProfileMonitorsUp(graph, element);
131 double spacing = DiagramGraphUtil.getProfileMonitorSpacing(graph, element);
132 return new MonitorTextGridResult(rowId(), name, "", "", enabled, up, spacing, null, null, null, transform, offset);
135 // Not to be modified
136 protected final static Point2D[] DEFAULT_CELL_OFFSETS = new Point2D[] {
137 new Point2D.Double(-45, 0),
138 new Point2D.Double(22, 0),
139 new Point2D.Double(24, 0)
142 // Not to be modified
143 protected final static Point2D[] ZERO_CELL_OFFSETS = new Point2D[] {
144 new Point2D.Double(0, 0),
145 new Point2D.Double(0, 0),
146 new Point2D.Double(0, 0)
149 protected Point2D[] getCellOffsets() {
150 return DEFAULT_CELL_OFFSETS;
154 public void applyStyleForNode(EvaluationContext observer, INode _node, MonitorTextGridResult result) {
156 String value = result != null ? result.getText1() : null;
157 boolean enabled = result != null ? result.getEnabled() : false;
159 if (value != null && enabled) {
161 // if (value != null && !value.isEmpty() && !value.trim().isEmpty()) {
163 String value2 = result != null ? result.getText2() : null;
164 String value3 = result != null ? result.getText3() : null;
166 double spacing = result.getSpacing();
168 final Function1<String, String> modifier = result != null ? result.getModifier() : null;
169 final Function1<String, String> validator = result != null ? result.getValidator() : null;
170 final Function1<Vec2d, Boolean> translator = result != null ? result.getTranslator() : null;
171 final RVI rvi = result != null ? result.getRVI() : null;
173 final TextGridNode node = ProfileVariables.claimChild(_node, "", "TextGridStyle", TextGridNode.class, observer);
177 // This assumes that this TextGridStyle instance will be devoted to
178 // this row ID until the end of its life.
179 // String id = result.getRowId();
180 // System.out.println(this + " ID: " + id);
181 // if (!id.equals(this.id)) {
182 // System.out.println(this + " SET ID: " + this.id + " -> " + id);
187 Integer newRow = observer.getTemporaryProperty(_node, "location");
191 // Remove from existing row to add to another row if necessary.
192 Integer row = getCurrentRowNumber(observer, _node);
193 if (row != null && row != newRow) {
194 String actualId = node.getRowId(row);
195 String id = observer.getProperty(_node, rowIdKey());
196 if (id.equals(actualId)) {
202 node.setRowId(row, result.getRowId());
204 setCurrentRowNumber(observer, _node, result.getRowId(), row);
206 observer.setTemporaryProperty(_node, "location", row + 1);
208 node.setText(2, row, value2);
209 node.setUp(result.getUp());
211 MonitorTextGridResult cache = node.getCache(1, row);
212 if(cache != null && cache.sameStructure(result)) return;
214 node.setCache(1, row, result);
216 boolean isConnection = _node instanceof ConnectionNode;
218 Rectangle2D elementBounds = isConnection ? EMPTY_BOUNDS : NodeUtil.getLocalElementBounds(_node);
219 if(elementBounds == null) {
220 new Exception("Cannot get local element bounds for node " + _node.toString()).printStackTrace();
221 // This is here for checking why getLocalElementBounds failed in the debugger.
222 NodeUtil.getLocalElementBounds(_node);
226 // System.err.println("elementBounds " + elementBounds);
227 // System.err.println("parentTransform " + result.getParentTransform());
229 AffineTransform at = getTransform(_node,result.getParentTransform(), elementBounds, row, result.getUp());
230 Vec2d offset = result.getOffset();
232 Point2D[] cellOffsets = getCellOffsets();
234 AffineTransform at1 = new AffineTransform(at);
235 at1.translate(cellOffsets[0].getX(),cellOffsets[0].getY());
236 AffineTransform at2 = new AffineTransform(at);
237 at2.translate(cellOffsets[1].getX()+spacing,cellOffsets[1].getY());
238 AffineTransform at3 = new AffineTransform(at);
239 at3.translate(cellOffsets[2].getX()+spacing,cellOffsets[2].getY());
241 at1.translate(offset.x, offset.y);
242 at2.translate(offset.x, offset.y);
243 at3.translate(offset.x, offset.y);
245 node.setTransform(1, row, at1);
246 node.setTransform(2, row, at2);
247 node.setTransform(3, row, at3);
249 Alignment[] alignments = result.getAlignments();
250 if(alignments != null) {
251 node.setHorizontalAlignment(1, row, (byte) alignments[0].ordinal());
252 node.setHorizontalAlignment(2, row, (byte) alignments[1].ordinal());
253 node.setHorizontalAlignment(3, row, (byte) alignments[2].ordinal());
255 node.setHorizontalAlignment(1, row, (byte) getAlignment(1).ordinal());
256 node.setHorizontalAlignment(2, row, (byte) getAlignment(2).ordinal());
257 node.setHorizontalAlignment(3, row, (byte) getAlignment(3).ordinal());
260 Alignment[] verticalAlignments = result.getVerticalAlignments();
261 if(verticalAlignments != null) {
262 node.setVerticalAlignment(1, row, (byte) verticalAlignments[0].ordinal());
263 node.setVerticalAlignment(2, row, (byte) verticalAlignments[1].ordinal());
264 node.setVerticalAlignment(3, row, (byte) verticalAlignments[2].ordinal());
266 node.setVerticalAlignment(1, row, (byte) getVerticalAlignment(1).ordinal());
267 node.setVerticalAlignment(2, row, (byte) getVerticalAlignment(2).ordinal());
268 node.setVerticalAlignment(3, row, (byte) getVerticalAlignment(3).ordinal());
271 node.setZIndex(3000);
273 org.simantics.common.color.Color color = result.getColor();
274 Color awtColor = color != null ? Colors.awt(color) : Color.DARK_GRAY;
275 Color bgColor = getBackgroundColor();
276 Font font = getFont();
278 setTextNodeData(node, 1, row, value, font, awtColor, bgColor);
279 setTextNodeData(node, 2, row, value2, result.getPending(), font, awtColor, bgColor);
280 setTextNodeData(node, 3, row, value3, font, awtColor, bgColor);
282 node.setEditable(1, row, false);
283 node.setForceEventListening(2, row, true);
284 node.setEditable(2, row, modifier != null);
285 node.setEditable(3, row, false);
287 final int finalRow = row;
289 if (modifier != null) {
290 node.setTextListener(2, row, new ITextListener() {
292 public void textChanged() {}
295 public void textEditingStarted() {}
298 public void textEditingCancelled() {
302 public void textEditingEnded() {
304 TextNode t = node.get(2, finalRow);
308 if(!t.getText().equals(t.getTextBeforeEdit()))
309 modifier.apply(t.getText());
314 node.setTextListener(2, row, null);
317 node.setInputValidator(2, row, validator);
318 node.setTranslator(translator);
320 node.setRVI(2, row, rvi);
322 postProcessNode(node, row);
325 cleanupStyleForNode(observer, _node);
329 private void setTextNodeData(TextGridNode node, int x, int y, String text, Font font, Color fgColor, Color bgColor) {
331 node.setText(x, y, text);
332 node.setFont(x, y, font);
333 node.setColor(x, y, fgColor);
334 node.setBackgroundColor(x, y, bgColor);
336 // Prevent rendering of the node.
337 node.setFont(x, y, null);
341 private void setTextNodeData(TextGridNode node, int x, int y, String text, boolean pending, Font font, Color fgColor, Color bgColor) {
342 setTextNodeData(node, x, y, text, font, fgColor, bgColor);
343 node.setPending(x, y, pending);
346 protected Font getFont() {
350 protected Color getBackgroundColor() {
351 return BACKGROUND_COLOR;
354 protected Alignment getAlignment(int column) {
356 case 1: return Alignment.TRAILING;
357 case 2: return Alignment.TRAILING;
358 case 3: return Alignment.LEADING;
359 default: return Alignment.LEADING;
363 protected Alignment getVerticalAlignment(int column) {
364 return Alignment.TRAILING;
368 protected void cleanupStyleForNode(EvaluationContext observer, INode _node) {
369 Integer row = getCurrentRowNumber(observer, _node);
370 //System.out.println(this + " cleanup(" + id + ", " + row + ")");
371 //System.out.println(element);
374 clearCurrentRowNumber(observer, _node);
375 TextGridNode node = ProfileVariables.browseChild(_node, "TextGridStyle");
380 private Integer getCurrentRowNumber(EvaluationContext observer, INode _node) {
381 String rowId = observer.getProperty(_node, rowIdKey());
382 return observer.getProperty(_node, rowId);
385 private void setCurrentRowNumber(EvaluationContext observer, INode _node, String rowId, int row) {
386 // Mapping style identity -> rowId (resourceId)
387 observer.setProperty(_node, rowIdKey(), rowId);
388 // Mapping rowId (resourceId) -> row number
389 observer.setProperty(_node, rowId, row);
392 private void clearCurrentRowNumber(EvaluationContext observer, INode _node) {
393 String rowId = observer.getProperty(_node, rowIdKey());
395 observer.setProperty(_node, rowIdKey(), null);
396 Integer row = observer.getProperty(_node, rowId);
398 observer.setProperty(_node, rowId, null);
403 protected void postProcessNode(TextGridNode node, int row) {
406 private String rowIdKey() {
407 return "style" + getIdentity().toString();