]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.diagram/src/org/simantics/diagram/profile/TextGridStyle.java
Fix diagram profiles to work with latest DB changes
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / profile / TextGridStyle.java
1 package org.simantics.diagram.profile;
2
3 import java.awt.Color;
4 import java.awt.Font;
5 import java.awt.geom.AffineTransform;
6 import java.awt.geom.Point2D;
7 import java.awt.geom.Rectangle2D;
8
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;
30
31 /**
32  * @author Antti Villberg
33  * @author Tuukka Lehtonen
34  */
35 public abstract class TextGridStyle extends StyleBase<MonitorTextGridResult> {
36
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);
40
41 //      // NOTE: this is a hack
42 //      String id;
43
44         protected double xOffset;
45         protected double yOffset;
46
47         public TextGridStyle(Resource r) {
48                 this(r, 0.0, 2.1);
49         }
50
51         public TextGridStyle(Resource r, double xOffset, double yOffset) {
52             super(r);
53                 this.xOffset = xOffset;
54                 this.yOffset = yOffset;
55         }
56
57         public Resource getPropertyRelation(ReadGraph g, Resource module) {
58         throw new Error("Fix this");
59         }
60
61         /**
62          * @return the name of the scene graph node to create to represent the text
63          *         element created by this style
64          */
65         public String getNodeName() {
66                 return getClass().getSimpleName();
67         }
68
69         /**
70          * Override to customize.
71          * 
72          * @param graph
73          * @param element
74          * @return
75          * @throws DatabaseException
76          */
77         protected Resource getConfigurationComponent(ReadGraph graph, Resource element) throws DatabaseException {
78                 ModelingResources mr = ModelingResources.getInstance(graph);
79                 Resource config = graph.getPossibleObject(element, mr.ElementToComponent);
80                 return config;
81         }
82
83         /**
84          * Override to customize.
85          * 
86          * @param graph
87          * @param element
88          * @return
89          * @throws DatabaseException
90          */
91         protected String getConfigurationComponentNameForElement(ReadGraph graph, Resource element) throws DatabaseException {
92                 Resource config = getConfigurationComponent(graph, element);
93                 if (config == null)
94                         return null;
95                 String name = graph.getPossibleRelatedValue(config, getPropertyRelation(graph,element), Bindings.STRING);
96                 return name;
97         }
98
99         public AffineTransform getTransform(INode node, AffineTransform parentTransform, Rectangle2D elementBounds, int location, boolean up) {
100                 return getTransform(parentTransform, elementBounds, location, up);
101         }
102
103         public AffineTransform getTransform(AffineTransform parentTransform, Rectangle2D elementBounds, int location, boolean up) {
104
105                 double scale = GeometryUtils.getScale(parentTransform);
106
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) 
110                                 );
111                 at.scale(0.15, 0.15);
112
113                 return at;
114
115         }
116
117         protected String rowId() {
118                 return "";
119         }
120
121         @Override
122         public MonitorTextGridResult calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration)
123                         throws DatabaseException {
124                 String name = getConfigurationComponentNameForElement(graph, element);
125                 if (name == null)
126                         return null;
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);
133         }
134
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)
140         };
141
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)
147         };
148
149         protected Point2D[] getCellOffsets() {
150                 return DEFAULT_CELL_OFFSETS;
151         }
152
153         @Override
154         public void applyStyleForNode(EvaluationContext observer, INode _node, MonitorTextGridResult result) {
155
156                 String value = result != null ? result.getText1() : null;
157                 boolean enabled = result != null ? result.getEnabled() : false;
158
159                 if (value != null && enabled) {
160
161                         //        if (value != null && !value.isEmpty() && !value.trim().isEmpty()) {
162
163                         String value2 = result != null ? result.getText2() : null;
164                         String value3 = result != null ? result.getText3() : null;
165
166                         double spacing = result.getSpacing();
167
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;
172
173                         final TextGridNode node = ProfileVariables.claimChild(_node, "", "TextGridStyle", TextGridNode.class, observer);
174                         if (node == null)
175                                 return;
176
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);
183 //                              this.id = id;
184 //                      }
185                         
186
187                         Integer newRow = observer.getTemporaryProperty(_node, "location");
188                         if (newRow == null)
189                                 newRow = 1;
190
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)) {
197                                         node.removeRow(row);
198                                 }
199                         }
200                         row = newRow;
201
202                         node.setRowId(row, result.getRowId());
203                         
204                         setCurrentRowNumber(observer, _node, result.getRowId(), row);
205                         
206                         observer.setTemporaryProperty(_node, "location", row + 1);
207
208                         node.setText(2, row, value2);
209                         node.setUp(result.getUp());
210
211                         MonitorTextGridResult cache = node.getCache(1, row);
212                         if(cache != null && cache.sameStructure(result)) return;
213
214                         node.setCache(1, row, result);
215
216                         boolean isConnection = _node instanceof ConnectionNode;
217
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);
223                                 return;
224                         }
225
226                         //            System.err.println("elementBounds " + elementBounds);
227                         //            System.err.println("parentTransform " + result.getParentTransform());
228
229                         AffineTransform at = getTransform(_node,result.getParentTransform(), elementBounds, row, result.getUp());
230                         Vec2d offset = result.getOffset();
231
232                         Point2D[] cellOffsets = getCellOffsets();
233
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());
240
241                         at1.translate(offset.x, offset.y);
242                         at2.translate(offset.x, offset.y);
243                         at3.translate(offset.x, offset.y);
244
245                         node.setTransform(1, row, at1);
246                         node.setTransform(2, row, at2);
247                         node.setTransform(3, row, at3);
248
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());
254                         } else {
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());
258                         }
259
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());
265                         } else {
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());
269                         }
270
271                         node.setZIndex(3000);
272
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();
277
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);
281
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);
286
287                         final int finalRow = row;
288
289                         if (modifier != null) {
290                                 node.setTextListener(2, row, new ITextListener() {
291                                         @Override
292                                         public void textChanged() {}
293
294                                         @Override
295                                         public void textEditingStarted() {}
296
297                                         @Override
298                                         public void textEditingCancelled() {
299                                         }
300
301                                         @Override
302                                         public void textEditingEnded() {
303
304                                                 TextNode t = node.get(2, finalRow);
305                                                 if (t == null)
306                                                         return;
307
308                                                 if(!t.getText().equals(t.getTextBeforeEdit()))
309                                                         modifier.apply(t.getText());
310
311                                         }
312                                 });
313                         } else {
314                                 node.setTextListener(2,  row,  null);
315                         }
316
317                         node.setInputValidator(2, row, validator);
318                         node.setTranslator(translator);
319
320                         node.setRVI(2, row, rvi);
321
322                         postProcessNode(node, row);
323
324                 } else {
325                         cleanupStyleForNode(observer, _node);
326                 }
327         }
328
329         private void setTextNodeData(TextGridNode node, int x, int y, String text, Font font, Color fgColor, Color bgColor) {
330                 if (text != null) {
331                         node.setText(x, y, text);
332                         node.setFont(x, y, font);
333                         node.setColor(x, y, fgColor);
334                         node.setBackgroundColor(x, y, bgColor);
335                 } else {
336                         // Prevent rendering of the node.
337                         node.setFont(x, y, null);
338                 }
339         }
340
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);
344         }
345
346         protected Font getFont() {
347                 return FONT;
348         }
349
350         protected Color getBackgroundColor() {
351                 return BACKGROUND_COLOR;
352         }
353
354         protected Alignment getAlignment(int column) {
355                 switch(column) {
356                 case 1: return Alignment.TRAILING;
357                 case 2: return Alignment.TRAILING;
358                 case 3: return Alignment.LEADING;
359                 default: return Alignment.LEADING;
360                 }
361         }
362
363         protected Alignment getVerticalAlignment(int column) {
364                 return Alignment.TRAILING;
365         }
366
367         @Override
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);
372                 if (row == null)
373                         return;
374                 clearCurrentRowNumber(observer, _node);
375                 TextGridNode node = ProfileVariables.browseChild(_node, "TextGridStyle");
376                 if (node != null)
377                         node.removeRow(row);
378         }
379         
380         private Integer getCurrentRowNumber(EvaluationContext observer, INode _node) {
381         String rowId = observer.getProperty(_node, rowIdKey());
382         return observer.getProperty(_node, rowId);
383         }
384
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);
390     }
391
392         private void clearCurrentRowNumber(EvaluationContext observer, INode _node) {
393         String rowId = observer.getProperty(_node, rowIdKey());
394         if(rowId != null) {
395             observer.setProperty(_node, rowIdKey(), null);
396             Integer row = observer.getProperty(_node, rowId);
397             if(row != null) {
398                 observer.setProperty(_node, rowId, null);
399             }
400         }
401     }
402
403         protected void postProcessNode(TextGridNode node, int row) {
404         }
405         
406         private String rowIdKey() {
407         return "style" + getIdentity().toString();
408         }
409
410 }