1 package org.simantics.diagram.profile;
\r
3 import java.awt.Color;
\r
4 import java.awt.Font;
\r
5 import java.awt.geom.AffineTransform;
\r
6 import java.awt.geom.Point2D;
\r
7 import java.awt.geom.Rectangle2D;
\r
9 import org.simantics.databoard.Bindings;
\r
10 import org.simantics.datatypes.literal.Vec2d;
\r
11 import org.simantics.db.ReadGraph;
\r
12 import org.simantics.db.Resource;
\r
13 import org.simantics.db.exception.DatabaseException;
\r
14 import org.simantics.db.layer0.variable.RVI;
\r
15 import org.simantics.db.layer0.variable.Variable;
\r
16 import org.simantics.diagram.elements.ITextListener;
\r
17 import org.simantics.diagram.elements.TextGridNode;
\r
18 import org.simantics.diagram.elements.TextNode;
\r
19 import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;
\r
20 import org.simantics.g2d.utils.Alignment;
\r
21 import org.simantics.modeling.ModelingResources;
\r
22 import org.simantics.scenegraph.INode;
\r
23 import org.simantics.scenegraph.g2d.nodes.ConnectionNode;
\r
24 import org.simantics.scenegraph.profile.EvaluationContext;
\r
25 import org.simantics.scenegraph.profile.common.ProfileVariables;
\r
26 import org.simantics.scenegraph.utils.GeometryUtils;
\r
27 import org.simantics.scenegraph.utils.NodeUtil;
\r
28 import org.simantics.scl.runtime.function.Function1;
\r
29 import org.simantics.ui.colors.Colors;
\r
32 * @author Antti Villberg
\r
33 * @author Tuukka Lehtonen
\r
35 public abstract class TextGridStyle extends StyleBase<MonitorTextGridResult> {
\r
37 private final Font FONT = Font.decode("Arial 12");
\r
38 private final Color BACKGROUND_COLOR = new Color(255, 255, 255, 192);
\r
39 private static final Rectangle2D EMPTY_BOUNDS = new Rectangle2D.Double(0, 0, 0, 0);
\r
41 // NOTE: this is a hack
\r
44 protected double xOffset;
\r
45 protected double yOffset;
\r
47 public TextGridStyle() {
\r
51 public TextGridStyle(double xOffset, double yOffset) {
\r
52 this.xOffset = xOffset;
\r
53 this.yOffset = yOffset;
\r
56 public Resource getPropertyRelation(ReadGraph g, Resource module) {
\r
57 throw new Error("Fix this");
\r
61 * @return the name of the scene graph node to create to represent the text
\r
62 * element created by this style
\r
64 public String getNodeName() {
\r
65 return getClass().getSimpleName();
\r
69 * Override to customize.
\r
74 * @throws DatabaseException
\r
76 protected Resource getConfigurationComponent(ReadGraph graph, Resource element) throws DatabaseException {
\r
77 ModelingResources mr = ModelingResources.getInstance(graph);
\r
78 Resource config = graph.getPossibleObject(element, mr.ElementToComponent);
\r
83 * Override to customize.
\r
88 * @throws DatabaseException
\r
90 protected String getConfigurationComponentNameForElement(ReadGraph graph, Resource element) throws DatabaseException {
\r
91 Resource config = getConfigurationComponent(graph, element);
\r
94 String name = graph.getPossibleRelatedValue(config, getPropertyRelation(graph,element), Bindings.STRING);
\r
98 public AffineTransform getTransform(INode node, AffineTransform parentTransform, Rectangle2D elementBounds, int location, boolean up) {
\r
99 return getTransform(parentTransform, elementBounds, location, up);
\r
102 public AffineTransform getTransform(AffineTransform parentTransform, Rectangle2D elementBounds, int location, boolean up) {
\r
104 double scale = GeometryUtils.getScale(parentTransform);
\r
106 AffineTransform at = AffineTransform.getTranslateInstance(
\r
107 parentTransform.getTranslateX() + elementBounds.getCenterX() * scale + xOffset,
\r
108 parentTransform.getTranslateY() + elementBounds.getMinY() * scale + yOffset*(location-1) + (up ? 0.0 : (2.0*yOffset) + elementBounds.getHeight() * scale)
\r
110 at.scale(0.15, 0.15);
\r
116 protected String rowId() {
\r
121 public MonitorTextGridResult calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration)
\r
122 throws DatabaseException {
\r
123 String name = getConfigurationComponentNameForElement(graph, element);
\r
126 AffineTransform transform = DiagramGraphUtil.getDynamicAffineTransform(graph, runtimeDiagram, element);
\r
127 Vec2d offset = DiagramGraphUtil.getOffset(graph, element);
\r
128 boolean enabled = !DiagramGraphUtil.getProfileMonitorsHidden(graph, element);
\r
129 boolean up = DiagramGraphUtil.getProfileMonitorsUp(graph, element);
\r
130 double spacing = DiagramGraphUtil.getProfileMonitorSpacing(graph, element);
\r
131 return new MonitorTextGridResult(rowId(), name, "", "", enabled, up, spacing, null, null, null, transform, offset);
\r
134 // Not to be modified
\r
135 protected final static Point2D[] DEFAULT_CELL_OFFSETS = new Point2D[] {
\r
136 new Point2D.Double(-45, 0),
\r
137 new Point2D.Double(22, 0),
\r
138 new Point2D.Double(24, 0)
\r
141 // Not to be modified
\r
142 protected final static Point2D[] ZERO_CELL_OFFSETS = new Point2D[] {
\r
143 new Point2D.Double(0, 0),
\r
144 new Point2D.Double(0, 0),
\r
145 new Point2D.Double(0, 0)
\r
148 protected Point2D[] getCellOffsets() {
\r
149 return DEFAULT_CELL_OFFSETS;
\r
153 public void applyStyleForNode(EvaluationContext observer, INode _node, MonitorTextGridResult result) {
\r
155 String value = result != null ? result.getText1() : null;
\r
156 boolean enabled = result != null ? result.getEnabled() : false;
\r
158 if (value != null && enabled) {
\r
160 // if (value != null && !value.isEmpty() && !value.trim().isEmpty()) {
\r
162 String value2 = result != null ? result.getText2() : null;
\r
163 String value3 = result != null ? result.getText3() : null;
\r
165 double spacing = result.getSpacing();
\r
167 final Function1<String, String> modifier = result != null ? result.getModifier() : null;
\r
168 final Function1<String, String> validator = result != null ? result.getValidator() : null;
\r
169 final Function1<Vec2d, Boolean> translator = result != null ? result.getTranslator() : null;
\r
170 final RVI rvi = result != null ? result.getRVI() : null;
\r
172 final TextGridNode node = ProfileVariables.claimChild(_node, "", "TextGridStyle", TextGridNode.class, observer);
\r
176 // This assumes that this TextGridStyle instance will be devoted to
\r
177 // this row ID until the end of its life.
\r
178 String id = result.getRowId();
\r
179 //System.out.println(this + " ID: " + id);
\r
180 if (!id.equals(this.id)) {
\r
181 //System.out.println(this + " SET ID: " + this.id + " -> " + id);
\r
185 Integer newRow = observer.getTemporaryProperty(_node, "location");
\r
186 if (newRow == null)
\r
189 // Remove from existing row to add to another row if necessary.
\r
190 Integer row = observer.getProperty(_node, id);
\r
191 if (row != null && row != newRow) {
\r
192 String actualId = node.getRowId(row);
\r
193 if (id.equals(actualId)) {
\r
194 node.removeRow(row);
\r
199 node.setRowId(row, id);
\r
200 observer.setProperty(_node, id, row);
\r
201 observer.setTemporaryProperty(_node, "location", row + 1);
\r
203 node.setText(2, row, value2);
\r
204 node.setUp(result.getUp());
\r
206 MonitorTextGridResult cache = node.getCache(1, row);
\r
207 if(cache != null && cache.sameStructure(result)) return;
\r
209 node.setCache(1, row, result);
\r
211 boolean isConnection = _node instanceof ConnectionNode;
\r
213 Rectangle2D elementBounds = isConnection ? EMPTY_BOUNDS : NodeUtil.getLocalElementBounds(_node);
\r
214 if(elementBounds == null) {
\r
215 new Exception("Cannot get local element bounds for node " + _node.toString()).printStackTrace();
\r
216 // This is here for checking why getLocalElementBounds failed in the debugger.
\r
217 NodeUtil.getLocalElementBounds(_node);
\r
221 // System.err.println("elementBounds " + elementBounds);
\r
222 // System.err.println("parentTransform " + result.getParentTransform());
\r
224 AffineTransform at = getTransform(_node,result.getParentTransform(), elementBounds, row, result.getUp());
\r
225 Vec2d offset = result.getOffset();
\r
227 Point2D[] cellOffsets = getCellOffsets();
\r
229 AffineTransform at1 = new AffineTransform(at);
\r
230 at1.translate(cellOffsets[0].getX(),cellOffsets[0].getY());
\r
231 AffineTransform at2 = new AffineTransform(at);
\r
232 at2.translate(cellOffsets[1].getX()+spacing,cellOffsets[1].getY());
\r
233 AffineTransform at3 = new AffineTransform(at);
\r
234 at3.translate(cellOffsets[2].getX()+spacing,cellOffsets[2].getY());
\r
236 at1.translate(offset.x, offset.y);
\r
237 at2.translate(offset.x, offset.y);
\r
238 at3.translate(offset.x, offset.y);
\r
240 node.setTransform(1, row, at1);
\r
241 node.setTransform(2, row, at2);
\r
242 node.setTransform(3, row, at3);
\r
244 Alignment[] alignments = result.getAlignments();
\r
245 if(alignments != null) {
\r
246 node.setHorizontalAlignment(1, row, (byte) alignments[0].ordinal());
\r
247 node.setHorizontalAlignment(2, row, (byte) alignments[1].ordinal());
\r
248 node.setHorizontalAlignment(3, row, (byte) alignments[2].ordinal());
\r
250 node.setHorizontalAlignment(1, row, (byte) getAlignment(1).ordinal());
\r
251 node.setHorizontalAlignment(2, row, (byte) getAlignment(2).ordinal());
\r
252 node.setHorizontalAlignment(3, row, (byte) getAlignment(3).ordinal());
\r
255 Alignment[] verticalAlignments = result.getVerticalAlignments();
\r
256 if(verticalAlignments != null) {
\r
257 node.setVerticalAlignment(1, row, (byte) verticalAlignments[0].ordinal());
\r
258 node.setVerticalAlignment(2, row, (byte) verticalAlignments[1].ordinal());
\r
259 node.setVerticalAlignment(3, row, (byte) verticalAlignments[2].ordinal());
\r
261 node.setVerticalAlignment(1, row, (byte) getVerticalAlignment(1).ordinal());
\r
262 node.setVerticalAlignment(2, row, (byte) getVerticalAlignment(2).ordinal());
\r
263 node.setVerticalAlignment(3, row, (byte) getVerticalAlignment(3).ordinal());
\r
266 node.setZIndex(3000);
\r
268 org.simantics.common.color.Color color = result.getColor();
\r
269 java.awt.Color awtColor = color != null ? Colors.awt(color) : Color.DARK_GRAY;
\r
271 setTextNodeData(node, 1, row, value, FONT, awtColor, BACKGROUND_COLOR);
\r
272 setTextNodeData(node, 2, row, value2, result.getPending(), FONT, awtColor, BACKGROUND_COLOR);
\r
273 setTextNodeData(node, 3, row, value3, FONT, awtColor, BACKGROUND_COLOR);
\r
275 node.setEditable(1, row, false);
\r
276 node.setForceEventListening(2, row, true);
\r
277 node.setEditable(2, row, modifier != null);
\r
278 node.setEditable(3, row, false);
\r
280 final int finalRow = row;
\r
282 if (modifier != null) {
\r
283 node.setTextListener(2, row, new ITextListener() {
\r
285 public void textChanged() {}
\r
288 public void textEditingStarted() {}
\r
291 public void textEditingCancelled() {
\r
295 public void textEditingEnded() {
\r
297 TextNode t = node.get(2, finalRow);
\r
301 if(!t.getText().equals(t.getTextBeforeEdit()))
\r
302 modifier.apply(t.getText());
\r
307 node.setTextListener(2, row, null);
\r
310 node.setInputValidator(2, row, validator);
\r
311 node.setTranslator(translator);
\r
313 node.setRVI(2, row, rvi);
\r
315 postProcessNode(node, row);
\r
318 cleanupStyleForNode(observer, _node);
\r
322 private void setTextNodeData(TextGridNode node, int x, int y, String text, Font font, Color fgColor, Color bgColor) {
\r
323 if (text != null) {
\r
324 node.setText(x, y, text);
\r
325 node.setFont(x, y, font);
\r
326 node.setColor(x, y, fgColor);
\r
327 node.setBackgroundColor(x, y, bgColor);
\r
329 // Prevent rendering of the node.
\r
330 node.setFont(x, y, null);
\r
334 private void setTextNodeData(TextGridNode node, int x, int y, String text, boolean pending, Font font, Color fgColor, Color bgColor) {
\r
335 setTextNodeData(node, x, y, text, font, fgColor, bgColor);
\r
336 node.setPending(x, y, pending);
\r
339 protected Alignment getAlignment(int column) {
\r
341 case 1: return Alignment.TRAILING;
\r
342 case 2: return Alignment.TRAILING;
\r
343 case 3: return Alignment.LEADING;
\r
344 default: return Alignment.LEADING;
\r
348 protected Alignment getVerticalAlignment(int column) {
\r
349 return Alignment.TRAILING;
\r
353 protected void cleanupStyleForNode(EvaluationContext observer, INode _node) {
\r
354 Integer row = observer.getProperty(_node, id);
\r
355 //System.out.println(this + " cleanup(" + id + ", " + row + ")");
\r
356 //System.out.println(element);
\r
359 observer.setProperty(_node, id, null);
\r
360 TextGridNode node = ProfileVariables.browseChild(_node, "TextGridStyle");
\r
362 node.removeRow(row);
\r
365 protected void postProcessNode(TextGridNode node, int row) {
\r