]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.modeling.template2d.ui/src/org/simantics/modeling/template2d/ui/diagram/adapter/DrawingFlagTableStyle.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.modeling.template2d.ui / src / org / simantics / modeling / template2d / ui / diagram / adapter / DrawingFlagTableStyle.java
index 079017e8f8135e96e9125e8c28218c5f9f599ce8..5c91160ebe33af7b52be93a845b471a713c940f2 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2012 Association for Decentralized Information Management in\r
- * Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.modeling.template2d.ui.diagram.adapter;\r
-\r
-import java.awt.BasicStroke;\r
-import java.awt.Color;\r
-import java.awt.Shape;\r
-import java.awt.Stroke;\r
-import java.awt.geom.AffineTransform;\r
-import java.awt.geom.Line2D;\r
-import java.awt.geom.Rectangle2D;\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.Collections;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-import java.util.Map.Entry;\r
-import java.util.TreeMap;\r
-import java.util.concurrent.atomic.AtomicReference;\r
-\r
-import org.simantics.Simantics;\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.databoard.annotations.Optional;\r
-import org.simantics.databoard.util.Bean;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.Session;\r
-import org.simantics.db.common.procedure.adapter.TransientCacheListener;\r
-import org.simantics.db.common.request.ResourceRead;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.layer0.variable.Variable;\r
-import org.simantics.db.layer0.variable.Variables;\r
-import org.simantics.diagram.elements.TextNode;\r
-import org.simantics.diagram.function.All;\r
-import org.simantics.diagram.function.PredefinedVariables;\r
-import org.simantics.diagram.profile.ProfileKeys;\r
-import org.simantics.diagram.profile.StyleBase;\r
-import org.simantics.diagram.stubs.DiagramResource;\r
-import org.simantics.g2d.diagram.IDiagram;\r
-import org.simantics.g2d.element.ElementClass;\r
-import org.simantics.g2d.element.ElementHints;\r
-import org.simantics.g2d.element.ElementUtils;\r
-import org.simantics.g2d.element.IElement;\r
-import org.simantics.g2d.element.SceneGraphNodeKey;\r
-import org.simantics.g2d.element.handler.ElementAdapter;\r
-import org.simantics.g2d.element.handler.FillColor;\r
-import org.simantics.g2d.element.handler.InternalSize;\r
-import org.simantics.g2d.element.handler.Outline;\r
-import org.simantics.g2d.element.handler.OutlineColorSpec;\r
-import org.simantics.g2d.element.handler.SceneGraph;\r
-import org.simantics.g2d.element.handler.SelectionSpecification;\r
-import org.simantics.g2d.element.handler.StrokeSpec;\r
-import org.simantics.g2d.element.handler.Transform;\r
-import org.simantics.g2d.element.handler.impl.StaticObjectAdapter;\r
-import org.simantics.g2d.element.impl.Element;\r
-import org.simantics.g2d.elementclass.NonCopyable;\r
-import org.simantics.g2d.scenegraph.SceneGraphConstants;\r
-import org.simantics.layer0.Layer0;\r
-import org.simantics.modeling.template2d.ui.function.DrawingTemplateInfo;\r
-import org.simantics.modeling.template2d.ui.function.FlagInfo;\r
-import org.simantics.modeling.template2d.ui.function.FlagTableColumnInfo;\r
-import org.simantics.modeling.template2d.ui.function.FlagTableInfo;\r
-import org.simantics.modeling.template2d.ui.function.MonitorInfo;\r
-import org.simantics.modeling.template2d.ui.function.TranslateFlag;\r
-import org.simantics.scenegraph.INode;\r
-import org.simantics.scenegraph.g2d.G2DParentNode;\r
-import org.simantics.scenegraph.g2d.G2DSceneGraph;\r
-import org.simantics.scenegraph.g2d.nodes.ShapeNode;\r
-import org.simantics.scenegraph.g2d.nodes.spatial.RTreeNode;\r
-import org.simantics.scenegraph.profile.DataNodeMap;\r
-import org.simantics.scenegraph.profile.EvaluationContext;\r
-import org.simantics.scenegraph.profile.common.ProfileVariables;\r
-import org.simantics.scenegraph.utils.NodeUtil;\r
-import org.simantics.ui.colors.Colors;\r
-import org.simantics.ui.fonts.Fonts;\r
-import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
-\r
-public class DrawingFlagTableStyle extends StyleBase<DrawingFlagTableStyle.StyleInfo> {\r
-\r
-       private static final boolean DEBUG_PAINT_ELEMENTS = false;\r
-\r
-       private static final String SLOT_TABLE_PREFIX    = "slotTable<";\r
-       private static final String SLOT_TABLE_SEPARATOR = ">";\r
-\r
-       private static final String SLOT_TABLE_ELEMENTS  = "slotTableElements";\r
-\r
-       private ElementClass rowElementClass;\r
-\r
-       public DrawingFlagTableStyle(ReadGraph graph) {\r
-               rowElementClass = ElementClass.compile(\r
-                               RowElementHandler.INSTANCE,\r
-                               RowElementSelectionHandler.INSTANCE,\r
-                               NonCopyable.INSTANCE,\r
-                               new StaticObjectAdapter(DiagramResource.getInstance(graph).Flag)\r
-               ).setId(RowElementHandler.class.getSimpleName());\r
-               if (DEBUG_PAINT_ELEMENTS)\r
-                       rowElementClass = rowElementClass.newClassWith(TestSceneGraph.INSTANCE);\r
-       }\r
-\r
-       public static class StyleInfo extends Bean {\r
-               public TreeMap<String, FlagTableInfo> name2table;\r
-               public List<FlagInfo> flags;\r
-               @Optional\r
-               public Resource template = null;\r
-               //public String digest = "";\r
-       };\r
-       \r
-       \r
-       \r
-       public static class FlagInfos extends ResourceRead<ArrayList<FlagInfo>> {\r
-           public FlagInfos(Resource diagram) {\r
-               super(diagram);\r
-           }\r
-\r
-           @Override\r
-           public ArrayList<FlagInfo> perform(ReadGraph g) throws DatabaseException {\r
-               ArrayList<FlagInfo> flagInfos = new ArrayList<FlagInfo>();\r
-               try {\r
-                       Layer0 L0 = Layer0.getInstance(g);\r
-                       DiagramResource DIA = DiagramResource.getInstance(g);\r
-\r
-                       Collection<Resource> children = g.getObjects(resource, L0.ConsistsOf);\r
-                       for (Resource child:children){\r
-                               if (!g.isInstanceOf(child, DIA.Flag))\r
-                                       continue;\r
-\r
-                               Resource flag = child;\r
-                               String tableName = g.getPossibleRelatedValue(flag, DIA.Flag_HasIOTableBinding, Bindings.STRING);\r
-                               Integer rowIndex = g.getPossibleRelatedValue(flag, DIA.Flag_HasIOTableRowIndex, Bindings.INTEGER);\r
-                               FlagInfo flagInfo = new FlagInfo();\r
-                               flagInfo.flag = flag;\r
-                               if (tableName != null && tableName.length() > 0)\r
-                                       flagInfo.flagTableName = tableName;\r
-                               flagInfo.flagTableRowIndex = rowIndex;\r
-                               flagInfos.add(flagInfo);\r
-                       }\r
-               } catch (Throwable e){\r
-                       e.printStackTrace(System.err);\r
-               }\r
-               return flagInfos;\r
-           }\r
-       }\r
-\r
-       @Override\r
-       public StyleInfo calculateStyle(ReadGraph graph, Resource runtimeDiagram,\r
-                       Resource entry, Resource diagram, Variable activeComposite)\r
-                       throws DatabaseException {\r
-               Resource template = All.getTemplate(graph, runtimeDiagram);\r
-               if (template == null)\r
-                       return null;\r
-               DiagramResource DIA = DiagramResource.getInstance(graph);\r
-               Resource diagram2 = graph.getPossibleObject(runtimeDiagram, DIA.RuntimeDiagram_HasConfiguration);\r
-\r
-               StyleInfo info = new StyleInfo();\r
-               DrawingTemplateInfo templateInfo = new DrawingTemplateInfo(template);\r
-               info.template = template;\r
-               info.name2table = graph.syncRequest(templateInfo, TransientCacheListener.<TreeMap<String, FlagTableInfo>> instance());\r
-               if (info.name2table == null)\r
-                   info.name2table = new TreeMap<String,FlagTableInfo>();\r
-               //info.digest = templateInfo.getDigest();\r
-               //System.err.println(templateInfo.getDigest());\r
-\r
-               info.flags = graph.syncRequest(new FlagInfos(diagram2), TransientCacheListener.<ArrayList<FlagInfo>> instance());\r
-               if (info.flags == null)\r
-                   info.flags = Collections.emptyList();\r
-               return info;\r
-       }\r
-       \r
-       @Override\r
-       public void applyStyleForItem(EvaluationContext evaluationContext, DataNodeMap map, Object item, StyleInfo info) {\r
-               if (info == null || info.flags == null || info.name2table == null)\r
-                       return;\r
-\r
-               cleanupStyleForItem(evaluationContext, map, item);\r
-\r
-               // render tables\r
-               Iterator<Entry<String,FlagTableInfo>> it = info.name2table.entrySet().iterator();\r
-               while(it.hasNext()) {\r
-                       Entry<String,FlagTableInfo> entry = it.next();\r
-                       String name = entry.getKey();\r
-                       FlagTableInfo table = entry.getValue();\r
-                       RenderTable com = new RenderTable(evaluationContext, table, name);\r
-                       com.perform();\r
-\r
-                       // render header texts\r
-                       RenderHeaderTexts com3 = new RenderHeaderTexts(evaluationContext, table, name);\r
-                       com3.perform();\r
-               }\r
-\r
-               // render texts of flags\r
-//             for (FlagInfo flagInfo : info.flags) {\r
-//                     RenderFlagTexts com2 = new RenderFlagTexts(evaluationContext, flagInfo, info.name2table);\r
-//                     com2.perform();\r
-//             }\r
-       }\r
-       \r
-\r
-       /**\r
-        * This is just for debugging where the invisible IO row elements are.\r
-        * Not intended to be enabled.\r
-        */\r
-       private static class TestSceneGraph implements SceneGraph {\r
-\r
-           private static final long serialVersionUID = 5749410674482131633L;\r
-\r
-           public static final TestSceneGraph INSTANCE = new TestSceneGraph();\r
-           private static final Key KEY_SG = new SceneGraphNodeKey(INode.class, "DEBUG_SG_NODE");\r
-\r
-           @Override\r
-           public void init(IElement e, G2DParentNode parent) {\r
-               ShapeNode node = parent.getOrCreateNode("debug", ShapeNode.class);\r
-               if (node != null) {\r
-                   node.setTransform(new AffineTransform(ElementUtils.getTransform(e)));\r
-                   node.setShape(ElementUtils.getElementBounds(e));\r
-                   node.setFill(true);\r
-                   node.setColor(Color.CYAN);\r
-                   e.setHint(KEY_SG, node);\r
-               }\r
-           }\r
-\r
-           @Override\r
-           public void cleanup(IElement e) {\r
-               ElementUtils.removePossibleNode(e, KEY_SG);\r
-           }\r
-\r
-       }\r
-       \r
-       \r
-    static class RowElementSelectionHandler implements SelectionSpecification {\r
-\r
-        /**\r
-                * \r
-                */\r
-               private static final long serialVersionUID = 2539536175525595035L;\r
-               \r
-               static final RowElementSelectionHandler INSTANCE = new RowElementSelectionHandler();\r
-\r
-\r
-        private RowElementSelectionHandler() {\r
-        }\r
-\r
-               @Override\r
-               public Object getAdapter(Class adapter) {\r
-                       // outline color\r
-                       if (adapter.equals(OutlineColorSpec.class)){\r
-                               return new OutlineColorSpec() {\r
-                                       /**\r
-                                        * \r
-                                        */\r
-                                       private static final long serialVersionUID = 2372559366005877243L;\r
-\r
-                                       @Override\r
-                                       public void setColor(IElement e, Color c) {\r
-                                       }\r
-\r
-                                       @Override\r
-                                       public Color getColor(IElement e) {\r
-                                               return new Color(10,10,10,40);\r
-                                       }\r
-                               };\r
-                       }\r
-                       if (adapter.equals(FillColor.class)){\r
-                               return new FillColor() {\r
-                                       /**\r
-                                        * \r
-                                        */\r
-                                       private static final long serialVersionUID = 558080965120741509L;\r
-\r
-                                       @Override\r
-                                       public void setFillColor(IElement e, Color c) {\r
-                                               // TODO Auto-generated method stub\r
-                                               \r
-                                       }\r
-\r
-                                       @Override\r
-                                       public Color getFillColor(IElement e) {\r
-                                               return new Color(10,10,10,40);\r
-                                       }\r
-                               };\r
-                       }\r
-                       if (adapter.equals(Outline.class)){\r
-                               return new Outline() {\r
-                                       /**\r
-                                        * \r
-                                        */\r
-                                       private static final long serialVersionUID = 272200345438045483L;\r
-\r
-                                       @Override\r
-                                       public Shape getElementShape(IElement e) {\r
-                                               return e.getHint(ElementHints.KEY_BOUNDS);\r
-                                       }\r
-                               };\r
-                       }\r
-                       if (adapter.equals(Transform.class)){\r
-                               return new Transform() {\r
-                                       /**\r
-                                        * \r
-                                        */\r
-                                       private static final long serialVersionUID = 7653122570884609688L;\r
-\r
-                                       @Override\r
-                                       public AffineTransform getTransform(IElement e) {\r
-                                               return e.getHint(ElementHints.KEY_TRANSFORM);\r
-                                       }\r
-\r
-                                       @Override\r
-                                       public void setTransform(IElement e, AffineTransform at) {\r
-                                       }\r
-                               };\r
-                       }\r
-                       if (adapter.equals(StrokeSpec.class)){\r
-                               return new StrokeSpec() {\r
-\r
-                                       /**\r
-                                        * \r
-                                        */\r
-                                       private static final long serialVersionUID = 1074910311375484373L;\r
-\r
-                                       @Override\r
-                                       public Stroke getStroke(IElement e) {\r
-                                               return new BasicStroke(0.15f, BasicStroke.CAP_SQUARE,\r
-                                                   BasicStroke.CAP_SQUARE, 10.0f,\r
-                                                   null, 0.0f);\r
-                                       }\r
-\r
-                                       @Override\r
-                                       public void setStroke(IElement e, Stroke at) {\r
-                                               // TODO Auto-generated method stub\r
-                                               \r
-                                       }\r
-                                       \r
-                               };\r
-                       }\r
-                       // TODO Auto-generated method stub\r
-                       return null;\r
-               }\r
-\r
-    }\r
-\r
-    \r
-    static class RowElementHandler implements InternalSize, Transform, ElementAdapter {\r
-\r
-        static final RowElementHandler INSTANCE = new RowElementHandler();\r
-\r
-        private static final long serialVersionUID = 829379327756475944L;\r
-\r
-        private RowElementHandler() {\r
-        }\r
-\r
-        @Override\r
-        public Rectangle2D getBounds(IElement e, Rectangle2D size) {\r
-            if (size == null)\r
-                size = new Rectangle2D.Double();\r
-            Rectangle2D r = e.getHint(ElementHints.KEY_BOUNDS);\r
-            size.setFrame(r);\r
-            return size;\r
-        }\r
-\r
-        @Override\r
-        public AffineTransform getTransform(IElement e) {\r
-            AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM);\r
-            return at != null ? at : new AffineTransform();\r
-        }\r
-\r
-        @Override\r
-        public void setTransform(IElement e, AffineTransform at) {\r
-            e.setHint(ElementHints.KEY_TRANSFORM, at.clone());\r
-        }\r
-\r
-        @SuppressWarnings("unchecked")\r
-        @Override\r
-        public <T> T adapt(IElement e, Class<T> toClass) {\r
-            if (toClass == Resource.class) {\r
-                Wrapper ref = e.getHint(ElementHints.KEY_OBJECT);\r
-                if (ref != null)\r
-                    return (T) ref.get();\r
-            }\r
-            return null;\r
-        }\r
-\r
-    }\r
-\r
-\r
-       public static class RenderHeaderTexts {\r
-               private FlagTableInfo table = null;\r
-               private String tableName = null;\r
-               private EvaluationContext evaluationContext = null;\r
-               \r
-               public RenderHeaderTexts(EvaluationContext evaluationContext, FlagTableInfo table, String tableName){\r
-                       this.table = table;\r
-                       this.tableName = tableName;\r
-                       this.evaluationContext = evaluationContext;\r
-               }\r
-               \r
-               public void perform(){\r
-                       if (table == null || evaluationContext == null || tableName == null)\r
-                               return;\r
-\r
-                       Session session = Simantics.peekSession();\r
-                       if (session == null)\r
-                               return;\r
-\r
-                       G2DSceneGraph sg = evaluationContext.getSceneGraph();\r
-                       if (sg == null)\r
-                               return;\r
-\r
-                       for (int k=0;k<table.columns.size();k++){\r
-                               FlagTableColumnInfo slotcolumn = table.columns.get(k);\r
-                               if (slotcolumn == null)\r
-                                       continue;\r
-\r
-                               List<MonitorInfo> monitorInfos = slotcolumn.columnHeaders;\r
-                               if (monitorInfos == null)\r
-                                       continue;\r
-\r
-                               int cellInx = 0;\r
-                               for (MonitorInfo slotColumnData:monitorInfos){\r
-                                       String cellNodeName = null;\r
-                                       cellNodeName = cellLookupName(tableName, k, 0, cellInx);\r
-                                       cellInx++;\r
-                                       TextNode cellNode = (TextNode) NodeUtil.lookup(sg, cellNodeName);\r
-                                       if (cellNode == null)\r
-                                               continue;\r
-                                       String txtValue = "";\r
-                                       if (slotColumnData != null && slotColumnData.getText() != null)\r
-                                               txtValue = slotColumnData.getText();\r
-                                       final String text = txtValue;\r
-\r
-                                       try {\r
-                                               String value = "";\r
-                                               if (slotColumnData.getResource() != null)\r
-                                                       value = Simantics.getSession().sync(new EvaluatePath(slotColumnData.getResource(), text)); // , TransientCacheListener.<String> instance()\r
-                                               if (value != null)\r
-                                                       cellNode.setText(value.toString());\r
-                                       } catch (DatabaseException e) {\r
-                                               // TODO Auto-generated catch block\r
-                                               e.printStackTrace();\r
-                                       }\r
-                                       \r
-                               }\r
-                                       \r
-\r
-                               \r
-                       }\r
-               }\r
-       }\r
-\r
-//     public class RenderFlagTexts {\r
-//             private FlagInfo flagInfo = null;\r
-//             private TreeMap<String, FlagTableInfo> tables = null;\r
-//             private EvaluationContext evaluationContext = null;\r
-//             \r
-//             public RenderFlagTexts(EvaluationContext evaluationContext, FlagInfo flagInfo, TreeMap<String, FlagTableInfo> tables){\r
-//                     this.flagInfo = flagInfo;\r
-//                     this.tables = tables;\r
-//                     this.evaluationContext = evaluationContext;\r
-//             }\r
-//             \r
-//             public void perform(){\r
-//                     Session session = Simantics.peekSession();\r
-//                     if (session == null)\r
-//                             return;\r
-//\r
-//                     FlagTableInfo table = tables.get(flagInfo.flagTableName);\r
-//                     if (table == null)\r
-//                             return;\r
-//\r
-//                     G2DSceneGraph sg = evaluationContext.getSceneGraph();\r
-//                     if (sg == null)\r
-//                             return;\r
-//\r
-//                     INode tableNode = sg.lookupNode(tableLookupName(flagInfo.flagTableName));\r
-//                     if (tableNode == null)\r
-//                             return;\r
-//\r
-//                     Rectangle2D rowBounds = new Rectangle2D.Double(0, table.getRowHeight()*flagInfo.flagTableRowIndex, table.getWidth(), table.getRowHeight());\r
-//                     rowBounds = GeometryUtils.transformShape(rowBounds, table.affineTransform).getBounds2D();\r
-//                     addFlagElement(evaluationContext, tableNode, rowBounds, flagInfo.flag);\r
-//\r
-//                     for (int k=0;k<table.columns.size();k++){\r
-//                             FlagTableColumnInfo slotcolumn = table.columns.get(k);\r
-//                             if (slotcolumn == null)\r
-//                                     continue;\r
-//                             \r
-//                             List<MonitorInfo> monitorInfos = slotcolumn.columnDatas;\r
-//                             if (monitorInfos == null)\r
-//                                     continue;\r
-//\r
-//                             int cellInx = 0;\r
-//                             for (MonitorInfo slotColumnData:monitorInfos){\r
-//                                     String cellNodeName = cellLookupName(flagInfo.flagTableName, k, flagInfo.flagTableRowIndex, cellInx);\r
-//                                     cellInx++;\r
-//                                     TextNode cellNode = (TextNode) NodeUtil.lookup(sg, cellNodeName);\r
-//                                     if (cellNode == null)\r
-//                                             continue;\r
-//\r
-//                                     String txtValue = "";\r
-//                                     if (slotColumnData != null && slotColumnData.getText() != null)\r
-//                                             txtValue = slotColumnData.getText();\r
-//                                     final String text = txtValue;\r
-//\r
-//                                     try {\r
-//                                             String value = null;\r
-//                                             if (slotcolumn.getType() != FlagTableColumnInfo.TYPE_ROW_NUMBERING)\r
-//                                                     value = Simantics.getSession().sync(new EvaluatePath(flagInfo.flag, text)); // , TransientCacheListener.<String> instance()\r
-//                                             if (value != null)\r
-//                                                     cellNode.setText(value.toString());\r
-//                                     } catch (DatabaseException e) {\r
-//                                             // TODO Auto-generated catch block\r
-//                                             e.printStackTrace();\r
-//                                     }\r
-//                             }\r
-//                     }\r
-//             }\r
-//     }\r
-       \r
-       public static class EvaluatePath extends ResourceRead<String> {\r
-               private String path = null;\r
-               \r
-           public EvaluatePath(Resource res, String path) {\r
-               super(res);\r
-               this.path = path;\r
-//             this.flagInfo = flagInfo;\r
-           }\r
-\r
-           @Override\r
-           public String perform(ReadGraph g) throws DatabaseException {\r
-               PredefinedVariables vars = PredefinedVariables.getInstance();\r
-               Variable resourceVariable = Variables.getVariable(g, resource);\r
-               //v = g.adapt(this.flag, Variable.class);\r
-               if (resourceVariable == null)\r
-                       return "";\r
-               Variable property = vars.getVariable(g, path, resource, resourceVariable);\r
-               Object value = null;\r
-               if (property == null)\r
-                       return "";\r
-               try {\r
-                       value = property.getValue(g);\r
-               } catch (DatabaseException ex){\r
-               }\r
-               if (value == null || !(value instanceof String))\r
-                       return "";\r
-               return value.toString();\r
-           }\r
-       }\r
-\r
-       public static class RenderTable {\r
-               private FlagTableInfo table = null;\r
-               private String tableName = null;\r
-               private EvaluationContext evaluationContext = null;\r
-\r
-               public  RenderTable(EvaluationContext evaluationContext, FlagTableInfo table, String tableName){\r
-                       this.table = table;\r
-                       this.evaluationContext = evaluationContext;\r
-                       this.tableName = tableName;\r
-               }\r
-\r
-               public void perform(){\r
-                       // render table \r
-                       G2DSceneGraph sg = evaluationContext.getSceneGraph();\r
-                       if (sg == null)\r
-                               return;\r
-                       G2DParentNode nav = (G2DParentNode) sg.getNode(SceneGraphConstants.NAVIGATION_NODE_NAME);\r
-                       if (nav == null)\r
-                               return;\r
-\r
-                       String tableNodeName = tableLookupName(tableName);\r
-                       RTreeNode tableNode = (RTreeNode) sg.getNode(tableNodeName);\r
-                       if (tableNode == null){\r
-                               tableNode = ProfileVariables.claimChild(evaluationContext.getSceneGraph(),\r
-                                               SceneGraphConstants.NAVIGATION_NODE_NAME, tableNodeName, RTreeNode.class, //SingleElementNode.class,\r
-                                               evaluationContext);\r
-                       }\r
-                       if (tableNode == null)\r
-                               return;\r
-                       tableNode.setTransform(new AffineTransform(table.affineTransform));\r
-                       //tableNode.setVisible(false);\r
-                       tableNode.setLookupId(tableNodeName);\r
-\r
-                       // Initialize row node book-keeping for this table\r
-                       evaluationContext.setProperty(tableNode, SLOT_TABLE_ELEMENTS, new ArrayList<IElement>());\r
-\r
-                       Integer rowCount = table.getRowCount();\r
-                       if (rowCount <= 0)\r
-                               return;\r
-\r
-                       // test if table is already generated\r
-                       String colNodeName = SLOT_TABLE_PREFIX + tableName + SLOT_TABLE_SEPARATOR + "0";\r
-                       RTreeNode colNode = (RTreeNode) sg.getNode(colNodeName);\r
-                       if (colNode != null) \r
-                               return;\r
-                       \r
-                       tableNode.setZIndex(2);\r
-\r
-                       //if (table.columns.size()> 0){\r
-                               // draw horisontal lines\r
-                               for (int k=-1;k<rowCount;k++){\r
-                                       int lineY = (int)(table.getRowHeight()*k+table.getRowHeight());\r
-                                       if (k==-1 || k+1 == rowCount){\r
-                                               this.addLine("line_" + k, 0, lineY, table.getWidth().intValue(), lineY, BasicStroke.CAP_BUTT, tableNode);\r
-                                               continue;\r
-                                       }\r
-                                       this.addLine("lineEnd_" + k, table.getWidth().intValue()-3, lineY, table.getWidth().intValue(), lineY, BasicStroke.CAP_BUTT, tableNode);\r
-                                       this.addLine("lineStart_" + k, 0, lineY, 3, lineY, BasicStroke.CAP_BUTT, tableNode);\r
-                               }\r
-                               {\r
-                                       // draw the first vertical line\r
-                                       int lineY = (int)(table.getRowHeight()*(rowCount));\r
-                                       this.addLine("bar_0", 0, 0, 0, lineY, BasicStroke.CAP_SQUARE, tableNode);\r
-                                       // draw the last vertical line\r
-                                       this.addLine("bar_last", (int)((double)table.getWidth()), 0, (int)((double)table.getWidth()), lineY, BasicStroke.CAP_SQUARE, tableNode);\r
-                               }\r
-                       //}\r
-\r
-                       // Support header row hiding when there are no header columns\r
-                       // defined\r
-                       int maxColumnHeaders = 0;\r
-                       if (table.columns.size() > 0) {\r
-                               for (FlagTableColumnInfo column : table.columns) {\r
-                                       maxColumnHeaders = Math.max(maxColumnHeaders, column.columnHeaders.size());\r
-                               }\r
-                       }\r
-\r
-                       // generate columns and cells\r
-                       String cellNodeName = null;\r
-                       TextNode cellNode = null;\r
-                       for (int k = 0;k<table.columns.size();k++){\r
-                               colNodeName = SLOT_TABLE_PREFIX + tableName + SLOT_TABLE_SEPARATOR + k;\r
-                               colNode = ProfileVariables.claimChild(evaluationContext.getSceneGraph(),\r
-                                               SceneGraphConstants.NAVIGATION_NODE_NAME+"."+tableNodeName, colNodeName, RTreeNode.class,\r
-                                               evaluationContext);\r
-                               if (colNode == null)\r
-                                       continue;\r
-                               double colX = 0.0;\r
-                               double colXAfter = 0.0;\r
-                               if (table.getWeightTotal() != 0.0){\r
-                                       double weightBefore = 0.0; \r
-                                       for (int m=0;m<k;m++){\r
-                                               FlagTableColumnInfo slotcolumn = table.columns.get(m);\r
-                                               if (slotcolumn == null || slotcolumn.getWeight() == Float.NaN)\r
-                                                       continue;\r
-                                               weightBefore = weightBefore + slotcolumn.getWeight();\r
-                                       }\r
-                                       FlagTableColumnInfo slotcolumn = table.columns.get(k);\r
-                                       colXAfter = ((weightBefore+slotcolumn.getWeight())/table.getWeightTotal())*table.getWidth(); \r
-                                       double procent = weightBefore/table.getWeightTotal();\r
-                                       colX = procent*table.getWidth();\r
-                                       colNode.setTransform(AffineTransform.getTranslateInstance(colX, 0.0));\r
-                               }\r
-                               \r
-                               // draw intermediate vertical lines\r
-//                             int lineY = (int)(table.getRowHeight()*(rowCount));\r
-//                             this.addLine("bar_" + (k+1), (int)colXAfter, 0, (int)colXAfter, lineY, BasicStroke.CAP_SQUARE, tableNode);\r
-                               \r
-                               FlagTableColumnInfo slotcolumn = table.columns.get(k);\r
-                               double cellProcent = slotcolumn.getWeight()/table.getWeightTotal();\r
-                               float cellWidth = (float)cellProcent*table.getWidth();\r
-                               if (cellWidth < 0.0)\r
-                                       cellWidth = 0.0F;\r
-                               if (cellWidth == 0.0F)\r
-                                       continue;\r
-                               \r
-                               for (int lineInx=0;lineInx<rowCount;lineInx++){\r
-                                       List<MonitorInfo> monitorInfos = slotcolumn.columnDatas;\r
-                                       if (lineInx < maxColumnHeaders)\r
-                                               monitorInfos = slotcolumn.columnHeaders;\r
-\r
-                                       int cellInx = 0;\r
-                                       for (MonitorInfo slotColumnData:monitorInfos){\r
-                                               cellNodeName = cellLookupName(tableName, k, lineInx, cellInx);\r
-                                               cellInx++;\r
-                                               cellNode = ProfileVariables.claimChild(evaluationContext.getSceneGraph(),\r
-                                                               SceneGraphConstants.NAVIGATION_NODE_NAME+"."+tableNodeName+"."+colNodeName, cellNodeName, TextNode.class,\r
-                                                               evaluationContext);\r
-                                               if (cellNode == null)\r
-                                                       continue;\r
-                                               cellNode.setLookupId(cellNodeName);\r
-\r
-                                               AffineTransform transform = new AffineTransform();\r
-                                               if (slotColumnData != null){\r
-                                                       if (slotColumnData.getFont() != null)\r
-                                                               cellNode.setFont(Fonts.awt(slotColumnData.getFont()));\r
-                                                       if (slotColumnData.getColor() != null)\r
-                                                               cellNode.setColor(Colors.awt(slotColumnData.getColor()));\r
-                                                       if (slotColumnData.getTransform() != null)\r
-                                                               transform = new AffineTransform(slotColumnData.getTransform());\r
-                                               }\r
-                                               cellNode.setVerticalAlignment((byte) 3);\r
-                                               double cellY = table.getRowHeight()*lineInx+DrawingTemplateInfo.BASELINE_VERTICAL_OFFSET*table.getRowHeight();\r
-                                               //cellNode.setText("yƅcolumn_" + k);\r
-                                               cellNode.setText("");\r
-                                               if (lineInx >= maxColumnHeaders && slotcolumn.getType() == FlagTableColumnInfo.TYPE_ROW_NUMBERING){\r
-                                                       // set row number\r
-                                                       cellNode.setText(new Integer(lineInx-maxColumnHeaders+slotcolumn.getStartOffset()).toString());\r
-                                                       cellNode.setHorizontalAlignment((byte) 0);\r
-                                               }\r
-\r
-//                                             FontMetrics metrics = new FontMetrics(cellNode.getFont());\r
-//                                             double dy = (metrics.getAscent() + metrics.getLeading())/2;\r
-                                               cellNode.setBorderWidth(0.f);\r
-                                               cellNode.setPadding(0.0, 0.0);\r
-                                               Rectangle2D bounds = cellNode.getBoundsInLocal();\r
-                                               //double dy = bounds.getHeight()/2.0;\r
-                                               transform.translate(0.0, cellY);\r
-                                               cellNode.setTransform(transform);\r
-                                               cellNode.setFixedWidth(cellWidth);\r
-                                       }\r
-                                       \r
-                               }\r
-                       }\r
-                       //tableNode.setVisible(true);\r
-               }\r
-               \r
-               void addLine(String nodeId, int x1, int y1, int x2, int y2, int cap, RTreeNode parent){\r
-                       Line2D line = new Line2D.Float(x1, y1, x2, y2);\r
-                       BasicStroke stroke = new BasicStroke(TranslateFlag.lineWidth, cap, BasicStroke.JOIN_MITER);\r
-                       ShapeNode shape = parent.addNode(nodeId, ShapeNode.class); // SingleElementNode\r
-                       shape.setShape(line);\r
-                       shape.setScaleStroke(false);\r
-                       shape.setStroke(stroke);\r
-                       shape.setFill(false);\r
-                       shape.setColor(new Color(0, 0, 0));\r
-                       shape.setZIndex(10);\r
-               }\r
-       }\r
-\r
-       protected void cleanupStyleForItem(EvaluationContext evaluationContext, DataNodeMap map, Object item) {\r
-               INode root = evaluationContext.getSceneGraph();\r
-               if (root instanceof G2DSceneGraph) {\r
-                       G2DSceneGraph sg = (G2DSceneGraph) root;\r
-                       G2DParentNode nav = (G2DParentNode) sg.getNode(SceneGraphConstants.NAVIGATION_NODE_NAME);\r
-\r
-//                     ProfileVariables.denyChildren(nav, SLOT_TABLE_PREFIX);\r
-\r
-                       IDiagram diagram = evaluationContext.getConstant(ProfileKeys.DIAGRAM);\r
-                       for (String childId : NodeUtil.filterDirectChildIds(nav, SLOT_TABLE_PREFIX)) {\r
-                           INode child = nav.getNode(childId);\r
-                           List<IElement> elements = evaluationContext.setProperty(child, SLOT_TABLE_ELEMENTS, null);\r
-                           if (elements != null && diagram != null)\r
-                               for (IElement e : elements)\r
-                                   cleanupElement(diagram, e);\r
-                           nav.removeNode(childId);\r
-                       }\r
-               }\r
-       }\r
-\r
-       private void cleanupElement(IDiagram diagram, IElement e) {\r
-               diagram.removeElement(e);\r
-       }\r
-\r
-    /**\r
-        * @param tableName slot table name\r
-        * @return lookup ID for the cell node\r
-        */\r
-       private static String tableLookupName(String tableName) {\r
-           return new StringBuilder()\r
-           .append(SLOT_TABLE_PREFIX)\r
-           .append(tableName).toString();\r
-       }\r
-\r
-       /**\r
-        * @param tableName slot table name\r
-        * @param column 0..C-1, where C is the amount of columns\r
-        * @param row 0..N, where 0 is header\r
-        * @return lookup ID for the cell node\r
-        */\r
-       private static String cellLookupName(String tableName, int column, int row, int index) {\r
-           return new StringBuilder()\r
-           .append(SLOT_TABLE_PREFIX)\r
-           .append(tableName)\r
-           .append(SLOT_TABLE_SEPARATOR)\r
-           .append(column)\r
-           .append(SLOT_TABLE_SEPARATOR)\r
-           .append(row)\r
-           .append(SLOT_TABLE_SEPARATOR)\r
-           .append(index).toString();\r
-       }\r
-\r
-    private IElement addFlagElement(EvaluationContext evaluationContext, INode tableNode, Rectangle2D bounds, Resource flag) {\r
-        IDiagram diagram = evaluationContext.getConstant(ProfileKeys.DIAGRAM);\r
-        assert diagram != null;\r
-        List<IElement> elements = evaluationContext.getProperty(tableNode, SLOT_TABLE_ELEMENTS);\r
-        assert elements != null;\r
-        IElement e = newFlagElement(evaluationContext, bounds, flag);\r
-        elements.add(e);\r
-        diagram.addElement(e);\r
-        return e;\r
-    }\r
-\r
-    private IElement newFlagElement(EvaluationContext evaluationContext, Rectangle2D bounds, Resource flag) {\r
-        IElement e = Element.spawnNew(rowElementClass);\r
-        e.setHint(ElementHints.KEY_BOUNDS, bounds.clone());\r
-        e.setHint(ElementHints.KEY_TRANSFORM, new AffineTransform());\r
-        // Just incase there's problems with same objects in multiple diagram elements\r
-        //e.setHint(ElementHints.KEY_OBJECT, flag);\r
-        // Didn't seem to help though.\r
-        e.setHint(ElementHints.KEY_OBJECT, new Wrapper(flag));\r
-        return e;\r
-    }\r
-\r
-    @Override\r
-    public String toString() {\r
-        return "Flag table style";\r
-    }\r
-\r
-    /**\r
-     * IO table flag elements need a wrapper KEY_OBJECT whose toString()\r
-     * produces something else besides {@link Resource#toString()}.\r
-     */\r
-    public static class Wrapper extends AtomicReference<Resource> {\r
-        private static final long serialVersionUID = -4041629837352874410L;\r
-        public Wrapper(Resource r) {\r
-            super(r);\r
-        }\r
-        @Override\r
-        public String toString() {\r
-            return "IO-" + super.toString();\r
-        }\r
-    }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2012 Association for Decentralized Information Management in
+ * Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.modeling.template2d.ui.diagram.adapter;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Line2D;
+import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.simantics.Simantics;
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.annotations.Optional;
+import org.simantics.databoard.util.Bean;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.Session;
+import org.simantics.db.common.procedure.adapter.TransientCacheListener;
+import org.simantics.db.common.request.ResourceRead;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.variable.Variable;
+import org.simantics.db.layer0.variable.Variables;
+import org.simantics.diagram.elements.TextNode;
+import org.simantics.diagram.function.All;
+import org.simantics.diagram.function.PredefinedVariables;
+import org.simantics.diagram.profile.ProfileKeys;
+import org.simantics.diagram.profile.StyleBase;
+import org.simantics.diagram.stubs.DiagramResource;
+import org.simantics.g2d.diagram.IDiagram;
+import org.simantics.g2d.element.ElementClass;
+import org.simantics.g2d.element.ElementHints;
+import org.simantics.g2d.element.ElementUtils;
+import org.simantics.g2d.element.IElement;
+import org.simantics.g2d.element.SceneGraphNodeKey;
+import org.simantics.g2d.element.handler.ElementAdapter;
+import org.simantics.g2d.element.handler.FillColor;
+import org.simantics.g2d.element.handler.InternalSize;
+import org.simantics.g2d.element.handler.Outline;
+import org.simantics.g2d.element.handler.OutlineColorSpec;
+import org.simantics.g2d.element.handler.SceneGraph;
+import org.simantics.g2d.element.handler.SelectionSpecification;
+import org.simantics.g2d.element.handler.StrokeSpec;
+import org.simantics.g2d.element.handler.Transform;
+import org.simantics.g2d.element.handler.impl.StaticObjectAdapter;
+import org.simantics.g2d.element.impl.Element;
+import org.simantics.g2d.elementclass.NonCopyable;
+import org.simantics.g2d.scenegraph.SceneGraphConstants;
+import org.simantics.layer0.Layer0;
+import org.simantics.modeling.template2d.ui.function.DrawingTemplateInfo;
+import org.simantics.modeling.template2d.ui.function.FlagInfo;
+import org.simantics.modeling.template2d.ui.function.FlagTableColumnInfo;
+import org.simantics.modeling.template2d.ui.function.FlagTableInfo;
+import org.simantics.modeling.template2d.ui.function.MonitorInfo;
+import org.simantics.modeling.template2d.ui.function.TranslateFlag;
+import org.simantics.scenegraph.INode;
+import org.simantics.scenegraph.g2d.G2DParentNode;
+import org.simantics.scenegraph.g2d.G2DSceneGraph;
+import org.simantics.scenegraph.g2d.nodes.ShapeNode;
+import org.simantics.scenegraph.g2d.nodes.spatial.RTreeNode;
+import org.simantics.scenegraph.profile.DataNodeMap;
+import org.simantics.scenegraph.profile.EvaluationContext;
+import org.simantics.scenegraph.profile.common.ProfileVariables;
+import org.simantics.scenegraph.utils.NodeUtil;
+import org.simantics.ui.colors.Colors;
+import org.simantics.ui.fonts.Fonts;
+import org.simantics.utils.datastructures.hints.IHintContext.Key;
+
+public class DrawingFlagTableStyle extends StyleBase<DrawingFlagTableStyle.StyleInfo> {
+
+       private static final boolean DEBUG_PAINT_ELEMENTS = false;
+
+       private static final String SLOT_TABLE_PREFIX    = "slotTable<";
+       private static final String SLOT_TABLE_SEPARATOR = ">";
+
+       private static final String SLOT_TABLE_ELEMENTS  = "slotTableElements";
+
+       private ElementClass rowElementClass;
+
+       public DrawingFlagTableStyle(ReadGraph graph) {
+               rowElementClass = ElementClass.compile(
+                               RowElementHandler.INSTANCE,
+                               RowElementSelectionHandler.INSTANCE,
+                               NonCopyable.INSTANCE,
+                               new StaticObjectAdapter(DiagramResource.getInstance(graph).Flag)
+               ).setId(RowElementHandler.class.getSimpleName());
+               if (DEBUG_PAINT_ELEMENTS)
+                       rowElementClass = rowElementClass.newClassWith(TestSceneGraph.INSTANCE);
+       }
+
+       public static class StyleInfo extends Bean {
+               public TreeMap<String, FlagTableInfo> name2table;
+               public List<FlagInfo> flags;
+               @Optional
+               public Resource template = null;
+               //public String digest = "";
+       };
+       
+       
+       
+       public static class FlagInfos extends ResourceRead<ArrayList<FlagInfo>> {
+           public FlagInfos(Resource diagram) {
+               super(diagram);
+           }
+
+           @Override
+           public ArrayList<FlagInfo> perform(ReadGraph g) throws DatabaseException {
+               ArrayList<FlagInfo> flagInfos = new ArrayList<FlagInfo>();
+               try {
+                       Layer0 L0 = Layer0.getInstance(g);
+                       DiagramResource DIA = DiagramResource.getInstance(g);
+
+                       Collection<Resource> children = g.getObjects(resource, L0.ConsistsOf);
+                       for (Resource child:children){
+                               if (!g.isInstanceOf(child, DIA.Flag))
+                                       continue;
+
+                               Resource flag = child;
+                               String tableName = g.getPossibleRelatedValue(flag, DIA.Flag_HasIOTableBinding, Bindings.STRING);
+                               Integer rowIndex = g.getPossibleRelatedValue(flag, DIA.Flag_HasIOTableRowIndex, Bindings.INTEGER);
+                               FlagInfo flagInfo = new FlagInfo();
+                               flagInfo.flag = flag;
+                               if (tableName != null && tableName.length() > 0)
+                                       flagInfo.flagTableName = tableName;
+                               flagInfo.flagTableRowIndex = rowIndex;
+                               flagInfos.add(flagInfo);
+                       }
+               } catch (Throwable e){
+                       e.printStackTrace(System.err);
+               }
+               return flagInfos;
+           }
+       }
+
+       @Override
+       public StyleInfo calculateStyle(ReadGraph graph, Resource runtimeDiagram,
+                       Resource entry, Resource diagram, Variable activeComposite)
+                       throws DatabaseException {
+               Resource template = All.getTemplate(graph, runtimeDiagram);
+               if (template == null)
+                       return null;
+               DiagramResource DIA = DiagramResource.getInstance(graph);
+               Resource diagram2 = graph.getPossibleObject(runtimeDiagram, DIA.RuntimeDiagram_HasConfiguration);
+
+               StyleInfo info = new StyleInfo();
+               DrawingTemplateInfo templateInfo = new DrawingTemplateInfo(template);
+               info.template = template;
+               info.name2table = graph.syncRequest(templateInfo, TransientCacheListener.<TreeMap<String, FlagTableInfo>> instance());
+               if (info.name2table == null)
+                   info.name2table = new TreeMap<String,FlagTableInfo>();
+               //info.digest = templateInfo.getDigest();
+               //System.err.println(templateInfo.getDigest());
+
+               info.flags = graph.syncRequest(new FlagInfos(diagram2), TransientCacheListener.<ArrayList<FlagInfo>> instance());
+               if (info.flags == null)
+                   info.flags = Collections.emptyList();
+               return info;
+       }
+       
+       @Override
+       public void applyStyleForItem(EvaluationContext evaluationContext, DataNodeMap map, Object item, StyleInfo info) {
+               if (info == null || info.flags == null || info.name2table == null)
+                       return;
+
+               cleanupStyleForItem(evaluationContext, map, item);
+
+               // render tables
+               Iterator<Entry<String,FlagTableInfo>> it = info.name2table.entrySet().iterator();
+               while(it.hasNext()) {
+                       Entry<String,FlagTableInfo> entry = it.next();
+                       String name = entry.getKey();
+                       FlagTableInfo table = entry.getValue();
+                       RenderTable com = new RenderTable(evaluationContext, table, name);
+                       com.perform();
+
+                       // render header texts
+                       RenderHeaderTexts com3 = new RenderHeaderTexts(evaluationContext, table, name);
+                       com3.perform();
+               }
+
+               // render texts of flags
+//             for (FlagInfo flagInfo : info.flags) {
+//                     RenderFlagTexts com2 = new RenderFlagTexts(evaluationContext, flagInfo, info.name2table);
+//                     com2.perform();
+//             }
+       }
+       
+
+       /**
+        * This is just for debugging where the invisible IO row elements are.
+        * Not intended to be enabled.
+        */
+       private static class TestSceneGraph implements SceneGraph {
+
+           private static final long serialVersionUID = 5749410674482131633L;
+
+           public static final TestSceneGraph INSTANCE = new TestSceneGraph();
+           private static final Key KEY_SG = new SceneGraphNodeKey(INode.class, "DEBUG_SG_NODE");
+
+           @Override
+           public void init(IElement e, G2DParentNode parent) {
+               ShapeNode node = parent.getOrCreateNode("debug", ShapeNode.class);
+               if (node != null) {
+                   node.setTransform(new AffineTransform(ElementUtils.getTransform(e)));
+                   node.setShape(ElementUtils.getElementBounds(e));
+                   node.setFill(true);
+                   node.setColor(Color.CYAN);
+                   e.setHint(KEY_SG, node);
+               }
+           }
+
+           @Override
+           public void cleanup(IElement e) {
+               ElementUtils.removePossibleNode(e, KEY_SG);
+           }
+
+       }
+       
+       
+    static class RowElementSelectionHandler implements SelectionSpecification {
+
+        /**
+                * 
+                */
+               private static final long serialVersionUID = 2539536175525595035L;
+               
+               static final RowElementSelectionHandler INSTANCE = new RowElementSelectionHandler();
+
+
+        private RowElementSelectionHandler() {
+        }
+
+               @Override
+               public Object getAdapter(Class adapter) {
+                       // outline color
+                       if (adapter.equals(OutlineColorSpec.class)){
+                               return new OutlineColorSpec() {
+                                       /**
+                                        * 
+                                        */
+                                       private static final long serialVersionUID = 2372559366005877243L;
+
+                                       @Override
+                                       public void setColor(IElement e, Color c) {
+                                       }
+
+                                       @Override
+                                       public Color getColor(IElement e) {
+                                               return new Color(10,10,10,40);
+                                       }
+                               };
+                       }
+                       if (adapter.equals(FillColor.class)){
+                               return new FillColor() {
+                                       /**
+                                        * 
+                                        */
+                                       private static final long serialVersionUID = 558080965120741509L;
+
+                                       @Override
+                                       public void setFillColor(IElement e, Color c) {
+                                               // TODO Auto-generated method stub
+                                               
+                                       }
+
+                                       @Override
+                                       public Color getFillColor(IElement e) {
+                                               return new Color(10,10,10,40);
+                                       }
+                               };
+                       }
+                       if (adapter.equals(Outline.class)){
+                               return new Outline() {
+                                       /**
+                                        * 
+                                        */
+                                       private static final long serialVersionUID = 272200345438045483L;
+
+                                       @Override
+                                       public Shape getElementShape(IElement e) {
+                                               return e.getHint(ElementHints.KEY_BOUNDS);
+                                       }
+                               };
+                       }
+                       if (adapter.equals(Transform.class)){
+                               return new Transform() {
+                                       /**
+                                        * 
+                                        */
+                                       private static final long serialVersionUID = 7653122570884609688L;
+
+                                       @Override
+                                       public AffineTransform getTransform(IElement e) {
+                                               return e.getHint(ElementHints.KEY_TRANSFORM);
+                                       }
+
+                                       @Override
+                                       public void setTransform(IElement e, AffineTransform at) {
+                                       }
+                               };
+                       }
+                       if (adapter.equals(StrokeSpec.class)){
+                               return new StrokeSpec() {
+
+                                       /**
+                                        * 
+                                        */
+                                       private static final long serialVersionUID = 1074910311375484373L;
+
+                                       @Override
+                                       public Stroke getStroke(IElement e) {
+                                               return new BasicStroke(0.15f, BasicStroke.CAP_SQUARE,
+                                                   BasicStroke.CAP_SQUARE, 10.0f,
+                                                   null, 0.0f);
+                                       }
+
+                                       @Override
+                                       public void setStroke(IElement e, Stroke at) {
+                                               // TODO Auto-generated method stub
+                                               
+                                       }
+                                       
+                               };
+                       }
+                       // TODO Auto-generated method stub
+                       return null;
+               }
+
+    }
+
+    
+    static class RowElementHandler implements InternalSize, Transform, ElementAdapter {
+
+        static final RowElementHandler INSTANCE = new RowElementHandler();
+
+        private static final long serialVersionUID = 829379327756475944L;
+
+        private RowElementHandler() {
+        }
+
+        @Override
+        public Rectangle2D getBounds(IElement e, Rectangle2D size) {
+            if (size == null)
+                size = new Rectangle2D.Double();
+            Rectangle2D r = e.getHint(ElementHints.KEY_BOUNDS);
+            size.setFrame(r);
+            return size;
+        }
+
+        @Override
+        public AffineTransform getTransform(IElement e) {
+            AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM);
+            return at != null ? at : new AffineTransform();
+        }
+
+        @Override
+        public void setTransform(IElement e, AffineTransform at) {
+            e.setHint(ElementHints.KEY_TRANSFORM, at.clone());
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <T> T adapt(IElement e, Class<T> toClass) {
+            if (toClass == Resource.class) {
+                Wrapper ref = e.getHint(ElementHints.KEY_OBJECT);
+                if (ref != null)
+                    return (T) ref.get();
+            }
+            return null;
+        }
+
+    }
+
+
+       public static class RenderHeaderTexts {
+               private FlagTableInfo table = null;
+               private String tableName = null;
+               private EvaluationContext evaluationContext = null;
+               
+               public RenderHeaderTexts(EvaluationContext evaluationContext, FlagTableInfo table, String tableName){
+                       this.table = table;
+                       this.tableName = tableName;
+                       this.evaluationContext = evaluationContext;
+               }
+               
+               public void perform(){
+                       if (table == null || evaluationContext == null || tableName == null)
+                               return;
+
+                       Session session = Simantics.peekSession();
+                       if (session == null)
+                               return;
+
+                       G2DSceneGraph sg = evaluationContext.getSceneGraph();
+                       if (sg == null)
+                               return;
+
+                       for (int k=0;k<table.columns.size();k++){
+                               FlagTableColumnInfo slotcolumn = table.columns.get(k);
+                               if (slotcolumn == null)
+                                       continue;
+
+                               List<MonitorInfo> monitorInfos = slotcolumn.columnHeaders;
+                               if (monitorInfos == null)
+                                       continue;
+
+                               int cellInx = 0;
+                               for (MonitorInfo slotColumnData:monitorInfos){
+                                       String cellNodeName = null;
+                                       cellNodeName = cellLookupName(tableName, k, 0, cellInx);
+                                       cellInx++;
+                                       TextNode cellNode = (TextNode) NodeUtil.lookup(sg, cellNodeName);
+                                       if (cellNode == null)
+                                               continue;
+                                       String txtValue = "";
+                                       if (slotColumnData != null && slotColumnData.getText() != null)
+                                               txtValue = slotColumnData.getText();
+                                       final String text = txtValue;
+
+                                       try {
+                                               String value = "";
+                                               if (slotColumnData.getResource() != null)
+                                                       value = Simantics.getSession().sync(new EvaluatePath(slotColumnData.getResource(), text)); // , TransientCacheListener.<String> instance()
+                                               if (value != null)
+                                                       cellNode.setText(value.toString());
+                                       } catch (DatabaseException e) {
+                                               // TODO Auto-generated catch block
+                                               e.printStackTrace();
+                                       }
+                                       
+                               }
+                                       
+
+                               
+                       }
+               }
+       }
+
+//     public class RenderFlagTexts {
+//             private FlagInfo flagInfo = null;
+//             private TreeMap<String, FlagTableInfo> tables = null;
+//             private EvaluationContext evaluationContext = null;
+//             
+//             public RenderFlagTexts(EvaluationContext evaluationContext, FlagInfo flagInfo, TreeMap<String, FlagTableInfo> tables){
+//                     this.flagInfo = flagInfo;
+//                     this.tables = tables;
+//                     this.evaluationContext = evaluationContext;
+//             }
+//             
+//             public void perform(){
+//                     Session session = Simantics.peekSession();
+//                     if (session == null)
+//                             return;
+//
+//                     FlagTableInfo table = tables.get(flagInfo.flagTableName);
+//                     if (table == null)
+//                             return;
+//
+//                     G2DSceneGraph sg = evaluationContext.getSceneGraph();
+//                     if (sg == null)
+//                             return;
+//
+//                     INode tableNode = sg.lookupNode(tableLookupName(flagInfo.flagTableName));
+//                     if (tableNode == null)
+//                             return;
+//
+//                     Rectangle2D rowBounds = new Rectangle2D.Double(0, table.getRowHeight()*flagInfo.flagTableRowIndex, table.getWidth(), table.getRowHeight());
+//                     rowBounds = GeometryUtils.transformShape(rowBounds, table.affineTransform).getBounds2D();
+//                     addFlagElement(evaluationContext, tableNode, rowBounds, flagInfo.flag);
+//
+//                     for (int k=0;k<table.columns.size();k++){
+//                             FlagTableColumnInfo slotcolumn = table.columns.get(k);
+//                             if (slotcolumn == null)
+//                                     continue;
+//                             
+//                             List<MonitorInfo> monitorInfos = slotcolumn.columnDatas;
+//                             if (monitorInfos == null)
+//                                     continue;
+//
+//                             int cellInx = 0;
+//                             for (MonitorInfo slotColumnData:monitorInfos){
+//                                     String cellNodeName = cellLookupName(flagInfo.flagTableName, k, flagInfo.flagTableRowIndex, cellInx);
+//                                     cellInx++;
+//                                     TextNode cellNode = (TextNode) NodeUtil.lookup(sg, cellNodeName);
+//                                     if (cellNode == null)
+//                                             continue;
+//
+//                                     String txtValue = "";
+//                                     if (slotColumnData != null && slotColumnData.getText() != null)
+//                                             txtValue = slotColumnData.getText();
+//                                     final String text = txtValue;
+//
+//                                     try {
+//                                             String value = null;
+//                                             if (slotcolumn.getType() != FlagTableColumnInfo.TYPE_ROW_NUMBERING)
+//                                                     value = Simantics.getSession().sync(new EvaluatePath(flagInfo.flag, text)); // , TransientCacheListener.<String> instance()
+//                                             if (value != null)
+//                                                     cellNode.setText(value.toString());
+//                                     } catch (DatabaseException e) {
+//                                             // TODO Auto-generated catch block
+//                                             e.printStackTrace();
+//                                     }
+//                             }
+//                     }
+//             }
+//     }
+       
+       public static class EvaluatePath extends ResourceRead<String> {
+               private String path = null;
+               
+           public EvaluatePath(Resource res, String path) {
+               super(res);
+               this.path = path;
+//             this.flagInfo = flagInfo;
+           }
+
+           @Override
+           public String perform(ReadGraph g) throws DatabaseException {
+               PredefinedVariables vars = PredefinedVariables.getInstance();
+               Variable resourceVariable = Variables.getVariable(g, resource);
+               //v = g.adapt(this.flag, Variable.class);
+               if (resourceVariable == null)
+                       return "";
+               Variable property = vars.getVariable(g, path, resource, resourceVariable);
+               Object value = null;
+               if (property == null)
+                       return "";
+               try {
+                       value = property.getValue(g);
+               } catch (DatabaseException ex){
+               }
+               if (value == null || !(value instanceof String))
+                       return "";
+               return value.toString();
+           }
+       }
+
+       public static class RenderTable {
+               private FlagTableInfo table = null;
+               private String tableName = null;
+               private EvaluationContext evaluationContext = null;
+
+               public  RenderTable(EvaluationContext evaluationContext, FlagTableInfo table, String tableName){
+                       this.table = table;
+                       this.evaluationContext = evaluationContext;
+                       this.tableName = tableName;
+               }
+
+               public void perform(){
+                       // render table 
+                       G2DSceneGraph sg = evaluationContext.getSceneGraph();
+                       if (sg == null)
+                               return;
+                       G2DParentNode nav = (G2DParentNode) sg.getNode(SceneGraphConstants.NAVIGATION_NODE_NAME);
+                       if (nav == null)
+                               return;
+
+                       String tableNodeName = tableLookupName(tableName);
+                       RTreeNode tableNode = (RTreeNode) sg.getNode(tableNodeName);
+                       if (tableNode == null){
+                               tableNode = ProfileVariables.claimChild(evaluationContext.getSceneGraph(),
+                                               SceneGraphConstants.NAVIGATION_NODE_NAME, tableNodeName, RTreeNode.class, //SingleElementNode.class,
+                                               evaluationContext);
+                       }
+                       if (tableNode == null)
+                               return;
+                       tableNode.setTransform(new AffineTransform(table.affineTransform));
+                       //tableNode.setVisible(false);
+                       tableNode.setLookupId(tableNodeName);
+
+                       // Initialize row node book-keeping for this table
+                       evaluationContext.setProperty(tableNode, SLOT_TABLE_ELEMENTS, new ArrayList<IElement>());
+
+                       Integer rowCount = table.getRowCount();
+                       if (rowCount <= 0)
+                               return;
+
+                       // test if table is already generated
+                       String colNodeName = SLOT_TABLE_PREFIX + tableName + SLOT_TABLE_SEPARATOR + "0";
+                       RTreeNode colNode = (RTreeNode) sg.getNode(colNodeName);
+                       if (colNode != null) 
+                               return;
+                       
+                       tableNode.setZIndex(2);
+
+                       //if (table.columns.size()> 0){
+                               // draw horisontal lines
+                               for (int k=-1;k<rowCount;k++){
+                                       int lineY = (int)(table.getRowHeight()*k+table.getRowHeight());
+                                       if (k==-1 || k+1 == rowCount){
+                                               this.addLine("line_" + k, 0, lineY, table.getWidth().intValue(), lineY, BasicStroke.CAP_BUTT, tableNode);
+                                               continue;
+                                       }
+                                       this.addLine("lineEnd_" + k, table.getWidth().intValue()-3, lineY, table.getWidth().intValue(), lineY, BasicStroke.CAP_BUTT, tableNode);
+                                       this.addLine("lineStart_" + k, 0, lineY, 3, lineY, BasicStroke.CAP_BUTT, tableNode);
+                               }
+                               {
+                                       // draw the first vertical line
+                                       int lineY = (int)(table.getRowHeight()*(rowCount));
+                                       this.addLine("bar_0", 0, 0, 0, lineY, BasicStroke.CAP_SQUARE, tableNode);
+                                       // draw the last vertical line
+                                       this.addLine("bar_last", (int)((double)table.getWidth()), 0, (int)((double)table.getWidth()), lineY, BasicStroke.CAP_SQUARE, tableNode);
+                               }
+                       //}
+
+                       // Support header row hiding when there are no header columns
+                       // defined
+                       int maxColumnHeaders = 0;
+                       if (table.columns.size() > 0) {
+                               for (FlagTableColumnInfo column : table.columns) {
+                                       maxColumnHeaders = Math.max(maxColumnHeaders, column.columnHeaders.size());
+                               }
+                       }
+
+                       // generate columns and cells
+                       String cellNodeName = null;
+                       TextNode cellNode = null;
+                       for (int k = 0;k<table.columns.size();k++){
+                               colNodeName = SLOT_TABLE_PREFIX + tableName + SLOT_TABLE_SEPARATOR + k;
+                               colNode = ProfileVariables.claimChild(evaluationContext.getSceneGraph(),
+                                               SceneGraphConstants.NAVIGATION_NODE_NAME+"."+tableNodeName, colNodeName, RTreeNode.class,
+                                               evaluationContext);
+                               if (colNode == null)
+                                       continue;
+                               double colX = 0.0;
+                               double colXAfter = 0.0;
+                               if (table.getWeightTotal() != 0.0){
+                                       double weightBefore = 0.0; 
+                                       for (int m=0;m<k;m++){
+                                               FlagTableColumnInfo slotcolumn = table.columns.get(m);
+                                               if (slotcolumn == null || slotcolumn.getWeight() == Float.NaN)
+                                                       continue;
+                                               weightBefore = weightBefore + slotcolumn.getWeight();
+                                       }
+                                       FlagTableColumnInfo slotcolumn = table.columns.get(k);
+                                       colXAfter = ((weightBefore+slotcolumn.getWeight())/table.getWeightTotal())*table.getWidth(); 
+                                       double procent = weightBefore/table.getWeightTotal();
+                                       colX = procent*table.getWidth();
+                                       colNode.setTransform(AffineTransform.getTranslateInstance(colX, 0.0));
+                               }
+                               
+                               // draw intermediate vertical lines
+//                             int lineY = (int)(table.getRowHeight()*(rowCount));
+//                             this.addLine("bar_" + (k+1), (int)colXAfter, 0, (int)colXAfter, lineY, BasicStroke.CAP_SQUARE, tableNode);
+                               
+                               FlagTableColumnInfo slotcolumn = table.columns.get(k);
+                               double cellProcent = slotcolumn.getWeight()/table.getWeightTotal();
+                               float cellWidth = (float)cellProcent*table.getWidth();
+                               if (cellWidth < 0.0)
+                                       cellWidth = 0.0F;
+                               if (cellWidth == 0.0F)
+                                       continue;
+                               
+                               for (int lineInx=0;lineInx<rowCount;lineInx++){
+                                       List<MonitorInfo> monitorInfos = slotcolumn.columnDatas;
+                                       if (lineInx < maxColumnHeaders)
+                                               monitorInfos = slotcolumn.columnHeaders;
+
+                                       int cellInx = 0;
+                                       for (MonitorInfo slotColumnData:monitorInfos){
+                                               cellNodeName = cellLookupName(tableName, k, lineInx, cellInx);
+                                               cellInx++;
+                                               cellNode = ProfileVariables.claimChild(evaluationContext.getSceneGraph(),
+                                                               SceneGraphConstants.NAVIGATION_NODE_NAME+"."+tableNodeName+"."+colNodeName, cellNodeName, TextNode.class,
+                                                               evaluationContext);
+                                               if (cellNode == null)
+                                                       continue;
+                                               cellNode.setLookupId(cellNodeName);
+
+                                               AffineTransform transform = new AffineTransform();
+                                               if (slotColumnData != null){
+                                                       if (slotColumnData.getFont() != null)
+                                                               cellNode.setFont(Fonts.awt(slotColumnData.getFont()));
+                                                       if (slotColumnData.getColor() != null)
+                                                               cellNode.setColor(Colors.awt(slotColumnData.getColor()));
+                                                       if (slotColumnData.getTransform() != null)
+                                                               transform = new AffineTransform(slotColumnData.getTransform());
+                                               }
+                                               cellNode.setVerticalAlignment((byte) 3);
+                                               double cellY = table.getRowHeight()*lineInx+DrawingTemplateInfo.BASELINE_VERTICAL_OFFSET*table.getRowHeight();
+                                               //cellNode.setText("yƅcolumn_" + k);
+                                               cellNode.setText("");
+                                               if (lineInx >= maxColumnHeaders && slotcolumn.getType() == FlagTableColumnInfo.TYPE_ROW_NUMBERING){
+                                                       // set row number
+                                                       cellNode.setText(new Integer(lineInx-maxColumnHeaders+slotcolumn.getStartOffset()).toString());
+                                                       cellNode.setHorizontalAlignment((byte) 0);
+                                               }
+
+//                                             FontMetrics metrics = new FontMetrics(cellNode.getFont());
+//                                             double dy = (metrics.getAscent() + metrics.getLeading())/2;
+                                               cellNode.setBorderWidth(0.f);
+                                               cellNode.setPadding(0.0, 0.0);
+                                               Rectangle2D bounds = cellNode.getBoundsInLocal();
+                                               //double dy = bounds.getHeight()/2.0;
+                                               transform.translate(0.0, cellY);
+                                               cellNode.setTransform(transform);
+                                               cellNode.setFixedWidth(cellWidth);
+                                       }
+                                       
+                               }
+                       }
+                       //tableNode.setVisible(true);
+               }
+               
+               void addLine(String nodeId, int x1, int y1, int x2, int y2, int cap, RTreeNode parent){
+                       Line2D line = new Line2D.Float(x1, y1, x2, y2);
+                       BasicStroke stroke = new BasicStroke(TranslateFlag.lineWidth, cap, BasicStroke.JOIN_MITER);
+                       ShapeNode shape = parent.addNode(nodeId, ShapeNode.class); // SingleElementNode
+                       shape.setShape(line);
+                       shape.setScaleStroke(false);
+                       shape.setStroke(stroke);
+                       shape.setFill(false);
+                       shape.setColor(new Color(0, 0, 0));
+                       shape.setZIndex(10);
+               }
+       }
+
+       protected void cleanupStyleForItem(EvaluationContext evaluationContext, DataNodeMap map, Object item) {
+               INode root = evaluationContext.getSceneGraph();
+               if (root instanceof G2DSceneGraph) {
+                       G2DSceneGraph sg = (G2DSceneGraph) root;
+                       G2DParentNode nav = (G2DParentNode) sg.getNode(SceneGraphConstants.NAVIGATION_NODE_NAME);
+
+//                     ProfileVariables.denyChildren(nav, SLOT_TABLE_PREFIX);
+
+                       IDiagram diagram = evaluationContext.getConstant(ProfileKeys.DIAGRAM);
+                       for (String childId : NodeUtil.filterDirectChildIds(nav, SLOT_TABLE_PREFIX)) {
+                           INode child = nav.getNode(childId);
+                           List<IElement> elements = evaluationContext.setProperty(child, SLOT_TABLE_ELEMENTS, null);
+                           if (elements != null && diagram != null)
+                               for (IElement e : elements)
+                                   cleanupElement(diagram, e);
+                           nav.removeNode(childId);
+                       }
+               }
+       }
+
+       private void cleanupElement(IDiagram diagram, IElement e) {
+               diagram.removeElement(e);
+       }
+
+    /**
+        * @param tableName slot table name
+        * @return lookup ID for the cell node
+        */
+       private static String tableLookupName(String tableName) {
+           return new StringBuilder()
+           .append(SLOT_TABLE_PREFIX)
+           .append(tableName).toString();
+       }
+
+       /**
+        * @param tableName slot table name
+        * @param column 0..C-1, where C is the amount of columns
+        * @param row 0..N, where 0 is header
+        * @return lookup ID for the cell node
+        */
+       private static String cellLookupName(String tableName, int column, int row, int index) {
+           return new StringBuilder()
+           .append(SLOT_TABLE_PREFIX)
+           .append(tableName)
+           .append(SLOT_TABLE_SEPARATOR)
+           .append(column)
+           .append(SLOT_TABLE_SEPARATOR)
+           .append(row)
+           .append(SLOT_TABLE_SEPARATOR)
+           .append(index).toString();
+       }
+
+    private IElement addFlagElement(EvaluationContext evaluationContext, INode tableNode, Rectangle2D bounds, Resource flag) {
+        IDiagram diagram = evaluationContext.getConstant(ProfileKeys.DIAGRAM);
+        assert diagram != null;
+        List<IElement> elements = evaluationContext.getProperty(tableNode, SLOT_TABLE_ELEMENTS);
+        assert elements != null;
+        IElement e = newFlagElement(evaluationContext, bounds, flag);
+        elements.add(e);
+        diagram.addElement(e);
+        return e;
+    }
+
+    private IElement newFlagElement(EvaluationContext evaluationContext, Rectangle2D bounds, Resource flag) {
+        IElement e = Element.spawnNew(rowElementClass);
+        e.setHint(ElementHints.KEY_BOUNDS, bounds.clone());
+        e.setHint(ElementHints.KEY_TRANSFORM, new AffineTransform());
+        // Just incase there's problems with same objects in multiple diagram elements
+        //e.setHint(ElementHints.KEY_OBJECT, flag);
+        // Didn't seem to help though.
+        e.setHint(ElementHints.KEY_OBJECT, new Wrapper(flag));
+        return e;
+    }
+
+    @Override
+    public String toString() {
+        return "Flag table style";
+    }
+
+    /**
+     * IO table flag elements need a wrapper KEY_OBJECT whose toString()
+     * produces something else besides {@link Resource#toString()}.
+     */
+    public static class Wrapper extends AtomicReference<Resource> {
+        private static final long serialVersionUID = -4041629837352874410L;
+        public Wrapper(Resource r) {
+            super(r);
+        }
+        @Override
+        public String toString() {
+            return "IO-" + super.toString();
+        }
+    }
+
+}