]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.template2d.ui/src/org/simantics/modeling/template2d/ui/diagram/adapter/DrawingFlagTableStyle.java
Added hashcode/equals methods to generic profile Group implementations
[simantics/platform.git] / bundles / org.simantics.modeling.template2d.ui / src / org / simantics / modeling / template2d / ui / diagram / adapter / DrawingFlagTableStyle.java
1 /*******************************************************************************
2  * Copyright (c) 2012 Association for Decentralized Information Management in
3  * Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.modeling.template2d.ui.diagram.adapter;
13
14 import java.awt.BasicStroke;
15 import java.awt.Color;
16 import java.awt.Shape;
17 import java.awt.Stroke;
18 import java.awt.geom.AffineTransform;
19 import java.awt.geom.Line2D;
20 import java.awt.geom.Rectangle2D;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Map.Entry;
27 import java.util.TreeMap;
28 import java.util.concurrent.atomic.AtomicReference;
29
30 import org.simantics.Simantics;
31 import org.simantics.databoard.Bindings;
32 import org.simantics.databoard.annotations.Optional;
33 import org.simantics.databoard.util.Bean;
34 import org.simantics.db.ReadGraph;
35 import org.simantics.db.Resource;
36 import org.simantics.db.Session;
37 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
38 import org.simantics.db.common.request.ResourceRead;
39 import org.simantics.db.exception.DatabaseException;
40 import org.simantics.db.layer0.variable.Variable;
41 import org.simantics.db.layer0.variable.Variables;
42 import org.simantics.diagram.elements.TextNode;
43 import org.simantics.diagram.function.All;
44 import org.simantics.diagram.function.PredefinedVariables;
45 import org.simantics.diagram.profile.ProfileKeys;
46 import org.simantics.diagram.profile.StyleBase;
47 import org.simantics.diagram.stubs.DiagramResource;
48 import org.simantics.g2d.diagram.IDiagram;
49 import org.simantics.g2d.element.ElementClass;
50 import org.simantics.g2d.element.ElementHints;
51 import org.simantics.g2d.element.ElementUtils;
52 import org.simantics.g2d.element.IElement;
53 import org.simantics.g2d.element.SceneGraphNodeKey;
54 import org.simantics.g2d.element.handler.ElementAdapter;
55 import org.simantics.g2d.element.handler.FillColor;
56 import org.simantics.g2d.element.handler.InternalSize;
57 import org.simantics.g2d.element.handler.Outline;
58 import org.simantics.g2d.element.handler.OutlineColorSpec;
59 import org.simantics.g2d.element.handler.SceneGraph;
60 import org.simantics.g2d.element.handler.SelectionSpecification;
61 import org.simantics.g2d.element.handler.StrokeSpec;
62 import org.simantics.g2d.element.handler.Transform;
63 import org.simantics.g2d.element.handler.impl.StaticObjectAdapter;
64 import org.simantics.g2d.element.impl.Element;
65 import org.simantics.g2d.elementclass.NonCopyable;
66 import org.simantics.g2d.scenegraph.SceneGraphConstants;
67 import org.simantics.layer0.Layer0;
68 import org.simantics.modeling.template2d.ui.function.DrawingTemplateInfo;
69 import org.simantics.modeling.template2d.ui.function.FlagInfo;
70 import org.simantics.modeling.template2d.ui.function.FlagTableColumnInfo;
71 import org.simantics.modeling.template2d.ui.function.FlagTableInfo;
72 import org.simantics.modeling.template2d.ui.function.MonitorInfo;
73 import org.simantics.modeling.template2d.ui.function.TranslateFlag;
74 import org.simantics.scenegraph.INode;
75 import org.simantics.scenegraph.g2d.G2DParentNode;
76 import org.simantics.scenegraph.g2d.G2DSceneGraph;
77 import org.simantics.scenegraph.g2d.nodes.ShapeNode;
78 import org.simantics.scenegraph.g2d.nodes.spatial.RTreeNode;
79 import org.simantics.scenegraph.profile.DataNodeMap;
80 import org.simantics.scenegraph.profile.EvaluationContext;
81 import org.simantics.scenegraph.profile.common.ProfileVariables;
82 import org.simantics.scenegraph.utils.NodeUtil;
83 import org.simantics.ui.colors.Colors;
84 import org.simantics.ui.fonts.Fonts;
85 import org.simantics.utils.datastructures.hints.IHintContext.Key;
86
87 public class DrawingFlagTableStyle extends StyleBase<DrawingFlagTableStyle.StyleInfo> {
88
89         private static final boolean DEBUG_PAINT_ELEMENTS = false;
90
91         private static final String SLOT_TABLE_PREFIX    = "slotTable<";
92         private static final String SLOT_TABLE_SEPARATOR = ">";
93
94         private static final String SLOT_TABLE_ELEMENTS  = "slotTableElements";
95
96         private ElementClass rowElementClass;
97
98         public DrawingFlagTableStyle(ReadGraph graph) {
99                 rowElementClass = ElementClass.compile(
100                                 RowElementHandler.INSTANCE,
101                                 RowElementSelectionHandler.INSTANCE,
102                                 NonCopyable.INSTANCE,
103                                 new StaticObjectAdapter(DiagramResource.getInstance(graph).Flag)
104                 ).setId(RowElementHandler.class.getSimpleName());
105                 if (DEBUG_PAINT_ELEMENTS)
106                         rowElementClass = rowElementClass.newClassWith(TestSceneGraph.INSTANCE);
107         }
108
109         public static class StyleInfo extends Bean {
110                 public TreeMap<String, FlagTableInfo> name2table;
111                 public List<FlagInfo> flags;
112                 @Optional
113                 public Resource template = null;
114                 //public String digest = "";
115         };
116         
117         
118         
119         public static class FlagInfos extends ResourceRead<ArrayList<FlagInfo>> {
120             public FlagInfos(Resource diagram) {
121                 super(diagram);
122             }
123
124             @Override
125             public ArrayList<FlagInfo> perform(ReadGraph g) throws DatabaseException {
126                 ArrayList<FlagInfo> flagInfos = new ArrayList<FlagInfo>();
127                 try {
128                         Layer0 L0 = Layer0.getInstance(g);
129                         DiagramResource DIA = DiagramResource.getInstance(g);
130
131                         Collection<Resource> children = g.getObjects(resource, L0.ConsistsOf);
132                         for (Resource child:children){
133                                 if (!g.isInstanceOf(child, DIA.Flag))
134                                         continue;
135
136                                 Resource flag = child;
137                                 String tableName = g.getPossibleRelatedValue(flag, DIA.Flag_HasIOTableBinding, Bindings.STRING);
138                                 Integer rowIndex = g.getPossibleRelatedValue(flag, DIA.Flag_HasIOTableRowIndex, Bindings.INTEGER);
139                                 FlagInfo flagInfo = new FlagInfo();
140                                 flagInfo.flag = flag;
141                                 if (tableName != null && tableName.length() > 0)
142                                         flagInfo.flagTableName = tableName;
143                                 flagInfo.flagTableRowIndex = rowIndex;
144                                 flagInfos.add(flagInfo);
145                         }
146                 } catch (Throwable e){
147                         e.printStackTrace(System.err);
148                 }
149                 return flagInfos;
150             }
151         }
152
153         @Override
154         public StyleInfo calculateStyle(ReadGraph graph, Resource runtimeDiagram,
155                         Resource entry, Resource diagram, Variable activeComposite)
156                         throws DatabaseException {
157                 Resource template = All.getTemplate(graph, runtimeDiagram);
158                 if (template == null)
159                         return null;
160                 DiagramResource DIA = DiagramResource.getInstance(graph);
161                 Resource diagram2 = graph.getPossibleObject(runtimeDiagram, DIA.RuntimeDiagram_HasConfiguration);
162
163                 StyleInfo info = new StyleInfo();
164                 DrawingTemplateInfo templateInfo = new DrawingTemplateInfo(template);
165                 info.template = template;
166                 info.name2table = graph.syncRequest(templateInfo, TransientCacheListener.<TreeMap<String, FlagTableInfo>> instance());
167                 if (info.name2table == null)
168                     info.name2table = new TreeMap<String,FlagTableInfo>();
169                 //info.digest = templateInfo.getDigest();
170                 //System.err.println(templateInfo.getDigest());
171
172                 info.flags = graph.syncRequest(new FlagInfos(diagram2), TransientCacheListener.<ArrayList<FlagInfo>> instance());
173                 if (info.flags == null)
174                     info.flags = Collections.emptyList();
175                 return info;
176         }
177         
178         @Override
179         public void applyStyleForItem(EvaluationContext evaluationContext, DataNodeMap map, Object item, StyleInfo info) {
180                 if (info == null || info.flags == null || info.name2table == null)
181                         return;
182
183                 cleanupStyleForItem(evaluationContext, map, item);
184
185                 // render tables
186                 Iterator<Entry<String,FlagTableInfo>> it = info.name2table.entrySet().iterator();
187                 while(it.hasNext()) {
188                         Entry<String,FlagTableInfo> entry = it.next();
189                         String name = entry.getKey();
190                         FlagTableInfo table = entry.getValue();
191                         RenderTable com = new RenderTable(evaluationContext, table, name);
192                         com.perform();
193
194                         // render header texts
195                         RenderHeaderTexts com3 = new RenderHeaderTexts(evaluationContext, table, name);
196                         com3.perform();
197                 }
198
199                 // render texts of flags
200 //              for (FlagInfo flagInfo : info.flags) {
201 //                      RenderFlagTexts com2 = new RenderFlagTexts(evaluationContext, flagInfo, info.name2table);
202 //                      com2.perform();
203 //              }
204         }
205         
206
207         /**
208          * This is just for debugging where the invisible IO row elements are.
209          * Not intended to be enabled.
210          */
211         private static class TestSceneGraph implements SceneGraph {
212
213             private static final long serialVersionUID = 5749410674482131633L;
214
215             public static final TestSceneGraph INSTANCE = new TestSceneGraph();
216             private static final Key KEY_SG = new SceneGraphNodeKey(INode.class, "DEBUG_SG_NODE");
217
218             @Override
219             public void init(IElement e, G2DParentNode parent) {
220                 ShapeNode node = parent.getOrCreateNode("debug", ShapeNode.class);
221                 if (node != null) {
222                     node.setTransform(new AffineTransform(ElementUtils.getTransform(e)));
223                     node.setShape(ElementUtils.getElementBounds(e));
224                     node.setFill(true);
225                     node.setColor(Color.CYAN);
226                     e.setHint(KEY_SG, node);
227                 }
228             }
229
230             @Override
231             public void cleanup(IElement e) {
232                 ElementUtils.removePossibleNode(e, KEY_SG);
233             }
234
235         }
236         
237         
238     static class RowElementSelectionHandler implements SelectionSpecification {
239
240         /**
241                  * 
242                  */
243                 private static final long serialVersionUID = 2539536175525595035L;
244                 
245                 static final RowElementSelectionHandler INSTANCE = new RowElementSelectionHandler();
246
247
248         private RowElementSelectionHandler() {
249         }
250
251                 @Override
252                 public Object getAdapter(Class adapter) {
253                         // outline color
254                         if (adapter.equals(OutlineColorSpec.class)){
255                                 return new OutlineColorSpec() {
256                                         /**
257                                          * 
258                                          */
259                                         private static final long serialVersionUID = 2372559366005877243L;
260
261                                         @Override
262                                         public void setColor(IElement e, Color c) {
263                                         }
264
265                                         @Override
266                                         public Color getColor(IElement e) {
267                                                 return new Color(10,10,10,40);
268                                         }
269                                 };
270                         }
271                         if (adapter.equals(FillColor.class)){
272                                 return new FillColor() {
273                                         /**
274                                          * 
275                                          */
276                                         private static final long serialVersionUID = 558080965120741509L;
277
278                                         @Override
279                                         public void setFillColor(IElement e, Color c) {
280                                                 // TODO Auto-generated method stub
281                                                 
282                                         }
283
284                                         @Override
285                                         public Color getFillColor(IElement e) {
286                                                 return new Color(10,10,10,40);
287                                         }
288                                 };
289                         }
290                         if (adapter.equals(Outline.class)){
291                                 return new Outline() {
292                                         /**
293                                          * 
294                                          */
295                                         private static final long serialVersionUID = 272200345438045483L;
296
297                                         @Override
298                                         public Shape getElementShape(IElement e) {
299                                                 return e.getHint(ElementHints.KEY_BOUNDS);
300                                         }
301                                 };
302                         }
303                         if (adapter.equals(Transform.class)){
304                                 return new Transform() {
305                                         /**
306                                          * 
307                                          */
308                                         private static final long serialVersionUID = 7653122570884609688L;
309
310                                         @Override
311                                         public AffineTransform getTransform(IElement e) {
312                                                 return e.getHint(ElementHints.KEY_TRANSFORM);
313                                         }
314
315                                         @Override
316                                         public void setTransform(IElement e, AffineTransform at) {
317                                         }
318                                 };
319                         }
320                         if (adapter.equals(StrokeSpec.class)){
321                                 return new StrokeSpec() {
322
323                                         /**
324                                          * 
325                                          */
326                                         private static final long serialVersionUID = 1074910311375484373L;
327
328                                         @Override
329                                         public Stroke getStroke(IElement e) {
330                                                 return new BasicStroke(0.15f, BasicStroke.CAP_SQUARE,
331                                                     BasicStroke.CAP_SQUARE, 10.0f,
332                                                     null, 0.0f);
333                                         }
334
335                                         @Override
336                                         public void setStroke(IElement e, Stroke at) {
337                                                 // TODO Auto-generated method stub
338                                                 
339                                         }
340                                         
341                                 };
342                         }
343                         // TODO Auto-generated method stub
344                         return null;
345                 }
346
347     }
348
349     
350     static class RowElementHandler implements InternalSize, Transform, ElementAdapter {
351
352         static final RowElementHandler INSTANCE = new RowElementHandler();
353
354         private static final long serialVersionUID = 829379327756475944L;
355
356         private RowElementHandler() {
357         }
358
359         @Override
360         public Rectangle2D getBounds(IElement e, Rectangle2D size) {
361             if (size == null)
362                 size = new Rectangle2D.Double();
363             Rectangle2D r = e.getHint(ElementHints.KEY_BOUNDS);
364             size.setFrame(r);
365             return size;
366         }
367
368         @Override
369         public AffineTransform getTransform(IElement e) {
370             AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM);
371             return at != null ? at : new AffineTransform();
372         }
373
374         @Override
375         public void setTransform(IElement e, AffineTransform at) {
376             e.setHint(ElementHints.KEY_TRANSFORM, at.clone());
377         }
378
379         @SuppressWarnings("unchecked")
380         @Override
381         public <T> T adapt(IElement e, Class<T> toClass) {
382             if (toClass == Resource.class) {
383                 Wrapper ref = e.getHint(ElementHints.KEY_OBJECT);
384                 if (ref != null)
385                     return (T) ref.get();
386             }
387             return null;
388         }
389
390     }
391
392
393         public static class RenderHeaderTexts {
394                 private FlagTableInfo table = null;
395                 private String tableName = null;
396                 private EvaluationContext evaluationContext = null;
397                 
398                 public RenderHeaderTexts(EvaluationContext evaluationContext, FlagTableInfo table, String tableName){
399                         this.table = table;
400                         this.tableName = tableName;
401                         this.evaluationContext = evaluationContext;
402                 }
403                 
404                 public void perform(){
405                         if (table == null || evaluationContext == null || tableName == null)
406                                 return;
407
408                         Session session = Simantics.peekSession();
409                         if (session == null)
410                                 return;
411
412                         G2DSceneGraph sg = evaluationContext.getSceneGraph();
413                         if (sg == null)
414                                 return;
415
416                         for (int k=0;k<table.columns.size();k++){
417                                 FlagTableColumnInfo slotcolumn = table.columns.get(k);
418                                 if (slotcolumn == null)
419                                         continue;
420
421                                 List<MonitorInfo> monitorInfos = slotcolumn.columnHeaders;
422                                 if (monitorInfos == null)
423                                         continue;
424
425                                 int cellInx = 0;
426                                 for (MonitorInfo slotColumnData:monitorInfos){
427                                         String cellNodeName = null;
428                                         cellNodeName = cellLookupName(tableName, k, 0, cellInx);
429                                         cellInx++;
430                                         TextNode cellNode = (TextNode) NodeUtil.lookup(sg, cellNodeName);
431                                         if (cellNode == null)
432                                                 continue;
433                                         String txtValue = "";
434                                         if (slotColumnData != null && slotColumnData.getText() != null)
435                                                 txtValue = slotColumnData.getText();
436                                         final String text = txtValue;
437
438                                         try {
439                                                 String value = "";
440                                                 if (slotColumnData.getResource() != null)
441                                                         value = Simantics.getSession().sync(new EvaluatePath(slotColumnData.getResource(), text)); // , TransientCacheListener.<String> instance()
442                                                 if (value != null)
443                                                         cellNode.setText(value.toString());
444                                         } catch (DatabaseException e) {
445                                                 // TODO Auto-generated catch block
446                                                 e.printStackTrace();
447                                         }
448                                         
449                                 }
450                                         
451
452                                 
453                         }
454                 }
455         }
456
457 //      public class RenderFlagTexts {
458 //              private FlagInfo flagInfo = null;
459 //              private TreeMap<String, FlagTableInfo> tables = null;
460 //              private EvaluationContext evaluationContext = null;
461 //              
462 //              public RenderFlagTexts(EvaluationContext evaluationContext, FlagInfo flagInfo, TreeMap<String, FlagTableInfo> tables){
463 //                      this.flagInfo = flagInfo;
464 //                      this.tables = tables;
465 //                      this.evaluationContext = evaluationContext;
466 //              }
467 //              
468 //              public void perform(){
469 //                      Session session = Simantics.peekSession();
470 //                      if (session == null)
471 //                              return;
472 //
473 //                      FlagTableInfo table = tables.get(flagInfo.flagTableName);
474 //                      if (table == null)
475 //                              return;
476 //
477 //                      G2DSceneGraph sg = evaluationContext.getSceneGraph();
478 //                      if (sg == null)
479 //                              return;
480 //
481 //                      INode tableNode = sg.lookupNode(tableLookupName(flagInfo.flagTableName));
482 //                      if (tableNode == null)
483 //                              return;
484 //
485 //                      Rectangle2D rowBounds = new Rectangle2D.Double(0, table.getRowHeight()*flagInfo.flagTableRowIndex, table.getWidth(), table.getRowHeight());
486 //                      rowBounds = GeometryUtils.transformShape(rowBounds, table.affineTransform).getBounds2D();
487 //                      addFlagElement(evaluationContext, tableNode, rowBounds, flagInfo.flag);
488 //
489 //                      for (int k=0;k<table.columns.size();k++){
490 //                              FlagTableColumnInfo slotcolumn = table.columns.get(k);
491 //                              if (slotcolumn == null)
492 //                                      continue;
493 //                              
494 //                              List<MonitorInfo> monitorInfos = slotcolumn.columnDatas;
495 //                              if (monitorInfos == null)
496 //                                      continue;
497 //
498 //                              int cellInx = 0;
499 //                              for (MonitorInfo slotColumnData:monitorInfos){
500 //                                      String cellNodeName = cellLookupName(flagInfo.flagTableName, k, flagInfo.flagTableRowIndex, cellInx);
501 //                                      cellInx++;
502 //                                      TextNode cellNode = (TextNode) NodeUtil.lookup(sg, cellNodeName);
503 //                                      if (cellNode == null)
504 //                                              continue;
505 //
506 //                                      String txtValue = "";
507 //                                      if (slotColumnData != null && slotColumnData.getText() != null)
508 //                                              txtValue = slotColumnData.getText();
509 //                                      final String text = txtValue;
510 //
511 //                                      try {
512 //                                              String value = null;
513 //                                              if (slotcolumn.getType() != FlagTableColumnInfo.TYPE_ROW_NUMBERING)
514 //                                                      value = Simantics.getSession().sync(new EvaluatePath(flagInfo.flag, text)); // , TransientCacheListener.<String> instance()
515 //                                              if (value != null)
516 //                                                      cellNode.setText(value.toString());
517 //                                      } catch (DatabaseException e) {
518 //                                              // TODO Auto-generated catch block
519 //                                              e.printStackTrace();
520 //                                      }
521 //                              }
522 //                      }
523 //              }
524 //      }
525         
526         public static class EvaluatePath extends ResourceRead<String> {
527                 private String path = null;
528                 
529             public EvaluatePath(Resource res, String path) {
530                 super(res);
531                 this.path = path;
532 //              this.flagInfo = flagInfo;
533             }
534
535             @Override
536             public String perform(ReadGraph g) throws DatabaseException {
537                 PredefinedVariables vars = PredefinedVariables.getInstance();
538                 Variable resourceVariable = Variables.getVariable(g, resource);
539                 //v = g.adapt(this.flag, Variable.class);
540                 if (resourceVariable == null)
541                         return "";
542                 Variable property = vars.getVariable(g, path, resource, resourceVariable);
543                 Object value = null;
544                 if (property == null)
545                         return "";
546                 try {
547                         value = property.getValue(g);
548                 } catch (DatabaseException ex){
549                 }
550                 if (value == null || !(value instanceof String))
551                         return "";
552                 return value.toString();
553             }
554         }
555
556         public static class RenderTable {
557                 private FlagTableInfo table = null;
558                 private String tableName = null;
559                 private EvaluationContext evaluationContext = null;
560
561                 public  RenderTable(EvaluationContext evaluationContext, FlagTableInfo table, String tableName){
562                         this.table = table;
563                         this.evaluationContext = evaluationContext;
564                         this.tableName = tableName;
565                 }
566
567                 public void perform(){
568                         // render table 
569                         G2DSceneGraph sg = evaluationContext.getSceneGraph();
570                         if (sg == null)
571                                 return;
572                         G2DParentNode nav = (G2DParentNode) sg.getNode(SceneGraphConstants.NAVIGATION_NODE_NAME);
573                         if (nav == null)
574                                 return;
575
576                         String tableNodeName = tableLookupName(tableName);
577                         RTreeNode tableNode = (RTreeNode) sg.getNode(tableNodeName);
578                         if (tableNode == null){
579                                 tableNode = ProfileVariables.claimChild(evaluationContext.getSceneGraph(),
580                                                 SceneGraphConstants.NAVIGATION_NODE_NAME, tableNodeName, RTreeNode.class, //SingleElementNode.class,
581                                                 evaluationContext);
582                         }
583                         if (tableNode == null)
584                                 return;
585                         tableNode.setTransform(new AffineTransform(table.affineTransform));
586                         //tableNode.setVisible(false);
587                         tableNode.setLookupId(tableNodeName);
588
589                         // Initialize row node book-keeping for this table
590                         evaluationContext.setProperty(tableNode, SLOT_TABLE_ELEMENTS, new ArrayList<IElement>());
591
592                         Integer rowCount = table.getRowCount();
593                         if (rowCount <= 0)
594                                 return;
595
596                         // test if table is already generated
597                         String colNodeName = SLOT_TABLE_PREFIX + tableName + SLOT_TABLE_SEPARATOR + "0";
598                         RTreeNode colNode = (RTreeNode) sg.getNode(colNodeName);
599                         if (colNode != null) 
600                                 return;
601                         
602                         tableNode.setZIndex(2);
603
604                         //if (table.columns.size()> 0){
605                                 // draw horisontal lines
606                                 for (int k=-1;k<rowCount;k++){
607                                         int lineY = (int)(table.getRowHeight()*k+table.getRowHeight());
608                                         if (k==-1 || k+1 == rowCount){
609                                                 this.addLine("line_" + k, 0, lineY, table.getWidth().intValue(), lineY, BasicStroke.CAP_BUTT, tableNode);
610                                                 continue;
611                                         }
612                                         this.addLine("lineEnd_" + k, table.getWidth().intValue()-3, lineY, table.getWidth().intValue(), lineY, BasicStroke.CAP_BUTT, tableNode);
613                                         this.addLine("lineStart_" + k, 0, lineY, 3, lineY, BasicStroke.CAP_BUTT, tableNode);
614                                 }
615                                 {
616                                         // draw the first vertical line
617                                         int lineY = (int)(table.getRowHeight()*(rowCount));
618                                         this.addLine("bar_0", 0, 0, 0, lineY, BasicStroke.CAP_SQUARE, tableNode);
619                                         // draw the last vertical line
620                                         this.addLine("bar_last", (int)((double)table.getWidth()), 0, (int)((double)table.getWidth()), lineY, BasicStroke.CAP_SQUARE, tableNode);
621                                 }
622                         //}
623
624                         // Support header row hiding when there are no header columns
625                         // defined
626                         int maxColumnHeaders = 0;
627                         if (table.columns.size() > 0) {
628                                 for (FlagTableColumnInfo column : table.columns) {
629                                         maxColumnHeaders = Math.max(maxColumnHeaders, column.columnHeaders.size());
630                                 }
631                         }
632
633                         // generate columns and cells
634                         String cellNodeName = null;
635                         TextNode cellNode = null;
636                         for (int k = 0;k<table.columns.size();k++){
637                                 colNodeName = SLOT_TABLE_PREFIX + tableName + SLOT_TABLE_SEPARATOR + k;
638                                 colNode = ProfileVariables.claimChild(evaluationContext.getSceneGraph(),
639                                                 SceneGraphConstants.NAVIGATION_NODE_NAME+"."+tableNodeName, colNodeName, RTreeNode.class,
640                                                 evaluationContext);
641                                 if (colNode == null)
642                                         continue;
643                                 double colX = 0.0;
644                                 double colXAfter = 0.0;
645                                 if (table.getWeightTotal() != 0.0){
646                                         double weightBefore = 0.0; 
647                                         for (int m=0;m<k;m++){
648                                                 FlagTableColumnInfo slotcolumn = table.columns.get(m);
649                                                 if (slotcolumn == null || slotcolumn.getWeight() == Float.NaN)
650                                                         continue;
651                                                 weightBefore = weightBefore + slotcolumn.getWeight();
652                                         }
653                                         FlagTableColumnInfo slotcolumn = table.columns.get(k);
654                                         colXAfter = ((weightBefore+slotcolumn.getWeight())/table.getWeightTotal())*table.getWidth(); 
655                                         double procent = weightBefore/table.getWeightTotal();
656                                         colX = procent*table.getWidth();
657                                         colNode.setTransform(AffineTransform.getTranslateInstance(colX, 0.0));
658                                 }
659                                 
660                                 // draw intermediate vertical lines
661 //                              int lineY = (int)(table.getRowHeight()*(rowCount));
662 //                              this.addLine("bar_" + (k+1), (int)colXAfter, 0, (int)colXAfter, lineY, BasicStroke.CAP_SQUARE, tableNode);
663                                 
664                                 FlagTableColumnInfo slotcolumn = table.columns.get(k);
665                                 double cellProcent = slotcolumn.getWeight()/table.getWeightTotal();
666                                 float cellWidth = (float)cellProcent*table.getWidth();
667                                 if (cellWidth < 0.0)
668                                         cellWidth = 0.0F;
669                                 if (cellWidth == 0.0F)
670                                         continue;
671                                 
672                                 for (int lineInx=0;lineInx<rowCount;lineInx++){
673                                         List<MonitorInfo> monitorInfos = slotcolumn.columnDatas;
674                                         if (lineInx < maxColumnHeaders)
675                                                 monitorInfos = slotcolumn.columnHeaders;
676
677                                         int cellInx = 0;
678                                         for (MonitorInfo slotColumnData:monitorInfos){
679                                                 cellNodeName = cellLookupName(tableName, k, lineInx, cellInx);
680                                                 cellInx++;
681                                                 cellNode = ProfileVariables.claimChild(evaluationContext.getSceneGraph(),
682                                                                 SceneGraphConstants.NAVIGATION_NODE_NAME+"."+tableNodeName+"."+colNodeName, cellNodeName, TextNode.class,
683                                                                 evaluationContext);
684                                                 if (cellNode == null)
685                                                         continue;
686                                                 cellNode.setLookupId(cellNodeName);
687
688                                                 AffineTransform transform = new AffineTransform();
689                                                 if (slotColumnData != null){
690                                                         if (slotColumnData.getFont() != null)
691                                                                 cellNode.setFont(Fonts.awt(slotColumnData.getFont()));
692                                                         if (slotColumnData.getColor() != null)
693                                                                 cellNode.setColor(Colors.awt(slotColumnData.getColor()));
694                                                         if (slotColumnData.getTransform() != null)
695                                                                 transform = new AffineTransform(slotColumnData.getTransform());
696                                                 }
697                                                 cellNode.setVerticalAlignment((byte) 3);
698                                                 double cellY = table.getRowHeight()*lineInx+DrawingTemplateInfo.BASELINE_VERTICAL_OFFSET*table.getRowHeight();
699                                                 //cellNode.setText("yƅcolumn_" + k);
700                                                 cellNode.setText("");
701                                                 if (lineInx >= maxColumnHeaders && slotcolumn.getType() == FlagTableColumnInfo.TYPE_ROW_NUMBERING){
702                                                         // set row number
703                                                         cellNode.setText(new Integer(lineInx-maxColumnHeaders+slotcolumn.getStartOffset()).toString());
704                                                         cellNode.setHorizontalAlignment((byte) 0);
705                                                 }
706
707 //                                              FontMetrics metrics = new FontMetrics(cellNode.getFont());
708 //                                              double dy = (metrics.getAscent() + metrics.getLeading())/2;
709                                                 cellNode.setBorderWidth(0.f);
710                                                 cellNode.setPadding(0.0, 0.0);
711                                                 Rectangle2D bounds = cellNode.getBoundsInLocal();
712                                                 //double dy = bounds.getHeight()/2.0;
713                                                 transform.translate(0.0, cellY);
714                                                 cellNode.setTransform(transform);
715                                                 cellNode.setFixedWidth(cellWidth);
716                                         }
717                                         
718                                 }
719                         }
720                         //tableNode.setVisible(true);
721                 }
722                 
723                 void addLine(String nodeId, int x1, int y1, int x2, int y2, int cap, RTreeNode parent){
724                         Line2D line = new Line2D.Float(x1, y1, x2, y2);
725                         BasicStroke stroke = new BasicStroke(TranslateFlag.lineWidth, cap, BasicStroke.JOIN_MITER);
726                         ShapeNode shape = parent.addNode(nodeId, ShapeNode.class); // SingleElementNode
727                         shape.setShape(line);
728                         shape.setScaleStroke(false);
729                         shape.setStroke(stroke);
730                         shape.setFill(false);
731                         shape.setColor(new Color(0, 0, 0));
732                         shape.setZIndex(10);
733                 }
734         }
735
736         protected void cleanupStyleForItem(EvaluationContext evaluationContext, DataNodeMap map, Object item) {
737                 INode root = evaluationContext.getSceneGraph();
738                 if (root instanceof G2DSceneGraph) {
739                         G2DSceneGraph sg = (G2DSceneGraph) root;
740                         G2DParentNode nav = (G2DParentNode) sg.getNode(SceneGraphConstants.NAVIGATION_NODE_NAME);
741
742 //                      ProfileVariables.denyChildren(nav, SLOT_TABLE_PREFIX);
743
744                         IDiagram diagram = evaluationContext.getConstant(ProfileKeys.DIAGRAM);
745                         for (String childId : NodeUtil.filterDirectChildIds(nav, SLOT_TABLE_PREFIX)) {
746                             INode child = nav.getNode(childId);
747                             List<IElement> elements = evaluationContext.setProperty(child, SLOT_TABLE_ELEMENTS, null);
748                             if (elements != null && diagram != null)
749                                 for (IElement e : elements)
750                                     cleanupElement(diagram, e);
751                             nav.removeNode(childId);
752                         }
753                 }
754         }
755
756         private void cleanupElement(IDiagram diagram, IElement e) {
757                 diagram.removeElement(e);
758         }
759
760     /**
761          * @param tableName slot table name
762          * @return lookup ID for the cell node
763          */
764         private static String tableLookupName(String tableName) {
765             return new StringBuilder()
766             .append(SLOT_TABLE_PREFIX)
767             .append(tableName).toString();
768         }
769
770         /**
771          * @param tableName slot table name
772          * @param column 0..C-1, where C is the amount of columns
773          * @param row 0..N, where 0 is header
774          * @return lookup ID for the cell node
775          */
776         private static String cellLookupName(String tableName, int column, int row, int index) {
777             return new StringBuilder()
778             .append(SLOT_TABLE_PREFIX)
779             .append(tableName)
780             .append(SLOT_TABLE_SEPARATOR)
781             .append(column)
782             .append(SLOT_TABLE_SEPARATOR)
783             .append(row)
784             .append(SLOT_TABLE_SEPARATOR)
785             .append(index).toString();
786         }
787
788     private IElement addFlagElement(EvaluationContext evaluationContext, INode tableNode, Rectangle2D bounds, Resource flag) {
789         IDiagram diagram = evaluationContext.getConstant(ProfileKeys.DIAGRAM);
790         assert diagram != null;
791         List<IElement> elements = evaluationContext.getProperty(tableNode, SLOT_TABLE_ELEMENTS);
792         assert elements != null;
793         IElement e = newFlagElement(evaluationContext, bounds, flag);
794         elements.add(e);
795         diagram.addElement(e);
796         return e;
797     }
798
799     private IElement newFlagElement(EvaluationContext evaluationContext, Rectangle2D bounds, Resource flag) {
800         IElement e = Element.spawnNew(rowElementClass);
801         e.setHint(ElementHints.KEY_BOUNDS, bounds.clone());
802         e.setHint(ElementHints.KEY_TRANSFORM, new AffineTransform());
803         // Just incase there's problems with same objects in multiple diagram elements
804         //e.setHint(ElementHints.KEY_OBJECT, flag);
805         // Didn't seem to help though.
806         e.setHint(ElementHints.KEY_OBJECT, new Wrapper(flag));
807         return e;
808     }
809
810     @Override
811     public String toString() {
812         return "Flag table style";
813     }
814
815     /**
816      * IO table flag elements need a wrapper KEY_OBJECT whose toString()
817      * produces something else besides {@link Resource#toString()}.
818      */
819     public static class Wrapper extends AtomicReference<Resource> {
820         private static final long serialVersionUID = -4041629837352874410L;
821         public Wrapper(Resource r) {
822             super(r);
823         }
824         @Override
825         public String toString() {
826             return "IO-" + super.toString();
827         }
828     }
829
830 }