]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/SpreadsheetBook.java
Spreadsheet updates cell values properly
[simantics/platform.git] / bundles / org.simantics.spreadsheet.graph / src / org / simantics / spreadsheet / graph / SpreadsheetBook.java
index e292fd91848659bcc4822dbc01604715f8a34212..d64d008edf713b1cfaf33a3e0fe28261bf188447 100644 (file)
-package org.simantics.spreadsheet.graph;\r
-\r
-import java.io.Serializable;\r
-import java.util.ArrayList;\r
-import java.util.Arrays;\r
-import java.util.Collection;\r
-import java.util.Collections;\r
-import java.util.HashMap;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Optional;\r
-\r
-import org.simantics.databoard.binding.mutable.Variant;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.layer0.StandardEngine;\r
-import org.simantics.spreadsheet.graph.formula.SpreadsheetEvaluationEnvironment;\r
-import org.simantics.spreadsheet.graph.synchronization.LineNodeUpdater;\r
-import org.simantics.spreadsheet.graph.synchronization.LineUpdater;\r
-import org.simantics.spreadsheet.graph.synchronization.NullUpdater;\r
-import org.simantics.spreadsheet.graph.synchronization.SheetLineComponent;\r
-import org.simantics.spreadsheet.graph.synchronization.StyleUpdater;\r
-import org.simantics.structural.synchronization.base.ComponentFactory;\r
-import org.simantics.structural.synchronization.base.MappingBase;\r
-import org.simantics.structural.synchronization.base.ModuleUpdaterBase;\r
-import org.simantics.structural.synchronization.base.ModuleUpdaterFactoryBase;\r
-import org.simantics.structural.synchronization.base.Solver;\r
-import org.simantics.structural.synchronization.base.SolverNameUtil;\r
-\r
-import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;\r
-import it.unimi.dsi.fastutil.longs.AbstractLongList;\r
-import it.unimi.dsi.fastutil.longs.AbstractLongSet;\r
-import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;\r
-import it.unimi.dsi.fastutil.longs.LongArraySet;\r
-import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet;\r
-\r
-public class SpreadsheetBook implements SpreadsheetElement<SpreadsheetElement, SpreadsheetElement>, StandardEngine<SheetNode>, Serializable, SheetNode<SpreadsheetEngine, SheetNode>, Solver, SolverNameUtil, ComponentFactory<SheetLineComponent>, ModuleUpdaterFactoryBase<SheetLineComponent> {\r
-\r
-       private static final long serialVersionUID = 7417208688311691396L;\r
-       \r
-       public Serializable NotAvailableError = new Serializable() {};\r
-       \r
-       public Long2ObjectOpenHashMap<AbstractLongSet> referenceMap = new Long2ObjectOpenHashMap<>();\r
-       \r
-       private Int2ObjectArrayMap<SpreadsheetStyle> styles = new Int2ObjectArrayMap<>();\r
-//     public ObjectArrayList<SpreadsheetStyle> styles = new ObjectArrayList<SpreadsheetStyle>();\r
-       public ArrayList<SpreadsheetEngine> sheets = new ArrayList<SpreadsheetEngine>();\r
-       \r
-       private SpreadsheetMapping mapping;\r
-       \r
-       \r
-       private int idCounter = 1;\r
-       \r
-       public SpreadsheetBook() {\r
-               getNewId(this);\r
-               mapping = new SpreadsheetMapping(new SheetLineComponent(""));\r
-       }\r
-       \r
-       public Map<Integer, SpreadsheetElement> children = new HashMap<>();\r
-\r
-       private boolean iterationEnabled;\r
-\r
-       public int getNewId(SpreadsheetElement element) {\r
-               int result = idCounter++;\r
-               children.put(result, element);\r
-               return result; \r
-       }\r
-       \r
-       public long getEngineIndex(SpreadsheetEngine engine) {\r
-               for(int i=0;i<sheets.size();i++)\r
-                       if(sheets.get(i) == engine) return i;\r
-               throw new IllegalStateException("Did not find sheet " + engine.getName());\r
-       }\r
-       \r
-       public void registerReferences(long cell, AbstractLongList refs) {\r
-               for(int i=0;i<refs.size();i++) {\r
-                       long key = refs.getLong(i);\r
-                       AbstractLongSet set = referenceMap.get(key);\r
-                       if(set == null) {\r
-                               set = new LongArraySet();\r
-                               referenceMap.put(key, set);\r
-                       }\r
-                       if(set.size() == 5) {\r
-                               AbstractLongSet newSet = new LongLinkedOpenHashSet();\r
-                               newSet.addAll(set);\r
-                               set = newSet;\r
-                               referenceMap.put(key, set);\r
-                       }\r
-                       set.add(cell);\r
-               }\r
-       }\r
-       \r
-       @Override\r
-       public Object getValue(SheetNode node) {\r
-               if(node instanceof SpreadsheetCellContent) {\r
-                       try {\r
-                               SpreadsheetCellContent scc = (SpreadsheetCellContent)node;\r
-                               Object content = scc.cell.evaluate(SpreadsheetEvaluationEnvironment.getInstance(this));\r
-                               if(content == null) return Variant.ofInstance("");\r
-                               if(content instanceof Variant) return content;\r
-                               else return Variant.ofInstance(content);\r
-                       } catch (Throwable t) {\r
-                               t.printStackTrace();\r
-                               return Variant.ofInstance(t.toString());\r
-                       }\r
-               } else if (node instanceof SpreadsheetCellContentExpression) {\r
-                       SpreadsheetCellContentExpression scce = (SpreadsheetCellContentExpression)node;\r
-                       if (scce.cell.content instanceof SpreadsheetFormula) {\r
-                       SpreadsheetFormula formula = (SpreadsheetFormula)scce.cell.content; \r
-                       return formula.expression;\r
-                       } else if (scce.cell.content instanceof SpreadsheetSCLConstant) {\r
-                           SpreadsheetSCLConstant sclConstant = (SpreadsheetSCLConstant) scce.cell.content;\r
-                           return "=" + sclConstant.expression;\r
-                       } else {\r
-                           System.out.println("Broken SpreadsheetCellContentExpression possibly due to overwriting an existing expression with a constant or something else (current content is " + scce.cell.content + ")");\r
-                           if (scce.cell.content instanceof Variant) {\r
-                               return scce.cell.content;\r
-                           } else {\r
-                               return Variant.ofInstance(scce.cell.content);\r
-                           }\r
-                       }\r
-               } else if (node instanceof SpreadsheetTypeNode) {\r
-                       SpreadsheetTypeNode stn = (SpreadsheetTypeNode)node;\r
-                       return stn.uri;\r
-               } else if (node instanceof SpreadsheetCellStyle) {\r
-                   int styleId = ((SpreadsheetCellStyle) node).cell.style;\r
-                   SpreadsheetStyle style = getStyle(styleId);\r
-                   if (style == null) {\r
-                       style = SpreadsheetStyle.empty();\r
-                       if (styleId != style.getStyleId())\r
-                           new Exception("different style ids!" + styleId + "  " + style.getStyleId()).printStackTrace();\r
-                       addStyle(style);\r
-                   }\r
-                   return style;\r
-               } else if (node instanceof SpreadsheetCellEditable) {\r
-                   boolean editable = ((SpreadsheetCellEditable) node).editable();\r
-                   return editable;\r
-               }\r
-               return null;\r
-       }\r
-\r
-       @Override\r
-       public void setValue(SheetNode node, Object value) {\r
-       }\r
-\r
-       @Override\r
-       public String getName(SheetNode node) {\r
-               return node.getName();\r
-       }\r
-\r
-       @Override\r
-       public Map<String, SheetNode> getChildren(SheetNode node) {\r
-               return node.getChildren();\r
-       }\r
-\r
-       @Override\r
-       public Map<String, SheetNode> getProperties(SheetNode node) {\r
-               return node.getProperties();\r
-       }\r
-\r
-       @Override\r
-       public String getName() {\r
-               return "";\r
-       }\r
-\r
-       @Override\r
-       public Map<String, SpreadsheetEngine> getChildren() {\r
-               Map<String,SpreadsheetEngine> result = new HashMap<String,SpreadsheetEngine>();\r
-               for(SpreadsheetEngine engine : sheets)\r
-                       result.put(engine.getName(), engine);\r
-               return result;\r
-       }\r
-\r
-       @Override\r
-       public Map<String, SheetNode> getProperties() {\r
-               return Collections.emptyMap();\r
-       }\r
-       \r
-       public SpreadsheetCell get(String sheet, int row, int column) {\r
-               SpreadsheetEngine engine = getEngine(sheet);\r
-               if(engine == null) return null;\r
-               SpreadsheetLine line = engine.getLine(row);\r
-               if(line == null) return null;\r
-               if(line.cells.size() <= column) return null;\r
-               return line.cells.get(column);\r
-       }\r
-\r
-       public SpreadsheetCell get(SpreadsheetEngine engine, int row, int column) {\r
-               SpreadsheetLine line = engine.getLine(row);\r
-               if(line == null) return null;\r
-               if(line.cells.size() <= column) return null;\r
-               return line.cells.get(column);\r
-       }\r
-\r
-       public SpreadsheetEngine getEngine(String sheet) {\r
-               for(SpreadsheetEngine engine : sheets)\r
-                       if(sheet.equals(engine.getName())) return engine;\r
-               return null;\r
-       }\r
-\r
-       @Override\r
-       public ModuleUpdaterBase<SheetLineComponent> createUpdater(String id) throws DatabaseException {\r
-               if("http://www.simantics.org/Spreadsheet-1.2/Line".equals(id))\r
-                       return new LineUpdater(id);\r
-               else if("http://www.simantics.org/Spreadsheet-1.2/LineNode".equals(id))\r
-                       return new LineNodeUpdater(id);\r
-               else if ("http://www.simantics.org/Spreadsheet-1.2/Style".equals(id))\r
-                   return new StyleUpdater(id);\r
-               else if("http://www.simantics.org/Spreadsheet-1.2/Lines".equals(id))\r
-                       return new NullUpdater(id);\r
-               else if("http://www.simantics.org/Spreadsheet-1.2/Spreadsheet".equals(id))\r
-                       return new NullUpdater(id);\r
-               else if("http://www.simantics.org/Spreadsheet-1.2/Book".equals(id))\r
-                       return new NullUpdater(id);\r
-               else\r
-                       throw new IllegalStateException("createUpdater " + id);\r
-       }\r
-\r
-       @Override\r
-       public SheetLineComponent create(String uid) {\r
-               return new SheetLineComponent(uid);\r
-       }\r
-\r
-       @Override\r
-       public String getFreshName(String parentName, String name) {\r
-               return parentName + "/" + name;\r
-       }\r
-\r
-       @Override\r
-       public String ensureNameIsVariationOf(String parentName, int id, String name) {\r
-           if (parentName.isEmpty())\r
-               return name;\r
-               return parentName + "/" + name;\r
-       }\r
-\r
-       final static int COMP_ROOT_POS = "COMP_ROOT/".length();\r
-       \r
-       @Override\r
-       public int getId(String name) {\r
-               \r
-               if("COMP_ROOT".equals(name)) return 1;\r
-\r
-               String path = name.substring(COMP_ROOT_POS);\r
-               String[] parts = path.split("/");\r
-               Object o = resolve(parts, 0);\r
-               if(o instanceof SpreadsheetLines) {\r
-                       return ((SpreadsheetLines)o).getId();\r
-               } else if(o instanceof SpreadsheetLine) {\r
-                       return ((SpreadsheetLine)o).getId();\r
-               } else if(o instanceof SpreadsheetEngine) {\r
-                       return ((SpreadsheetEngine)o).getId();\r
-               } else if (o instanceof SpreadsheetStyle) {\r
-                   return ((SpreadsheetStyle) o).getId();\r
-               }\r
-               \r
-               throw new IllegalStateException("Resolved object for parts " + Arrays.toString(parts) + " is not the right type! It is " + o);\r
-               \r
-       }\r
-       \r
-       Object resolve(String[] parts, int index) {\r
-               String part = parts[index];\r
-               if (part.startsWith("Style")) {\r
-                   for (SpreadsheetStyle style : styles.values()) {\r
-                       if (style.name.equals(part)) {\r
-                           return style;\r
-                       }\r
-                   }\r
-               }\r
-               SpreadsheetEngine engine = getEngine(part);\r
-               if(engine == null) return 0;\r
-               if(index == parts.length-1) return engine;\r
-               else return engine.resolve(parts, index+1);\r
-       }\r
-\r
-       @Override\r
-       public String getName(int id) {\r
-               if(id == -2) return "http://www.simantics.org/Spreadsheet-1.2/Book";\r
-               else if(id == -3) return "http://www.simantics.org/Spreadsheet-1.2/Spreadsheet";\r
-               else if(id == -4) return "http://www.simantics.org/Spreadsheet-1.2/Lines";\r
-               else if(id == -5)\r
-                   return "http://www.simantics.org/Spreadsheet-1.2/LineNode";\r
-               else if (id == -6)\r
-                   return "http://www.simantics.org/Spreadsheet-1.2/Line";\r
-               else if(id == -7)\r
-                   return "http://www.simantics.org/Spreadsheet-1.2/Style";\r
-               else return "" + id;\r
-       }\r
-\r
-       @Override\r
-       public int getModuleType(int id) {\r
-               Serializable s = children.get(id);\r
-               if(s instanceof SpreadsheetBook) return -2;\r
-               else if(s instanceof SpreadsheetEngine) return -3;\r
-               else if(s instanceof SpreadsheetLines) {\r
-                       if("Lines".equals(((SpreadsheetLines) s).getName()))\r
-                               return -4;\r
-                       else\r
-                               return -5;\r
-               }\r
-               else if(s instanceof SpreadsheetLine)\r
-                   return -6;\r
-               else if (s instanceof SpreadsheetStyle)\r
-                   return -7;\r
-               else throw new IllegalStateException();\r
-       }\r
-\r
-       @Override\r
-       public void remove(int id) {\r
-           \r
-           SpreadsheetElement child = children.get(id);\r
-           Optional<SpreadsheetElement> parent = child.getParent();\r
-           \r
-           if (parent.isPresent()) {\r
-               parent.get().remove(child);\r
-               children.remove(id);\r
-           }\r
-       }\r
-\r
-       @Override\r
-       public void addSubprocess(String name) {\r
-               ensureSubprocess(name);\r
-       }\r
-       \r
-       public <T> T ensureSubprocess(String name) {\r
-               String[] parts = name.split("/");\r
-               if(parts.length == 2) {\r
-                       SpreadsheetEngine engine = getEngine(parts[1]);\r
-                       if(engine == null) {\r
-                               engine = new SpreadsheetEngine(this, parts[1]);\r
-                               sheets.add(engine);\r
-                       }\r
-                       return (T)engine;\r
-               } else if (parts.length > 2) {\r
-                       SpreadsheetEngine engine = getEngine(parts[1]);\r
-                       return (T)engine.ensureSubprocess(parts, 2);\r
-               }\r
-               throw new IllegalStateException();\r
-       }\r
-       \r
-\r
-       @Override\r
-       public void includeSubprocess(String parentName, String subprocessName) {\r
-               // Nop\r
-       }\r
-\r
-       @Override\r
-       public <T> T getConcreteSolver() {\r
-               return (T)this;\r
-       }\r
-       \r
-       @Override\r
-       public void accept(SpreadsheetVisitor v) {\r
-               v.visit(this);\r
-       }\r
-       \r
-       public List<SpreadsheetCell> invalidate(SpreadsheetCell cell) {\r
-               ArrayList<SpreadsheetCell> result = new ArrayList<>();\r
-               result.add(cell);\r
-               cell.invalidate();\r
-               long refKey = cell.makeReferenceKey();\r
-               AbstractLongSet refs = referenceMap.remove(refKey);\r
-               if(refs == null) return result;\r
-               for(long ref : refs) {\r
-                       long sheet = ref >> 40;\r
-                       long row = (ref >> 20) & 0xFFFFF;\r
-                       long col = (ref) & 0xFFFFF;\r
-                       SpreadsheetCell referer = get(sheets.get((int)sheet), (int)row, (int)col);\r
-                       invalidate(referer);\r
-                       result.add(referer);\r
-               }\r
-               return result;\r
-       }\r
-\r
-    public void addStyle(SpreadsheetStyle style) {\r
-        if (style.name == null) {\r
-            new Exception("Trying to add style to book without name!!").printStackTrace();\r
-            return;\r
-        }\r
-        style.setSynchronizationId(getNewId(style));\r
-        styles.put(style.getStyleId(), style);\r
-    }\r
-\r
-    public SpreadsheetStyle getStyle(int styleId) {\r
-        return styles.get(styleId);\r
-    }\r
-\r
-    public MappingBase<SheetLineComponent> getMapping() {\r
-        return mapping;\r
-    }\r
-\r
-    @Override\r
-    public Optional<SpreadsheetElement> getParent() {\r
-        return Optional.empty();\r
-    }\r
-\r
-    @Override\r
-    public Collection<SpreadsheetElement> getSpreadsheetChildren() {\r
-        return children.values();\r
-    }\r
-\r
-    @Override\r
-    public void remove(SpreadsheetElement child) {\r
-        // TODO Auto-generated method stub\r
-        \r
-    }\r
-\r
-       public void setIterationEnabled(boolean value) {\r
-               this.iterationEnabled = value;\r
-       }\r
-       \r
-       public boolean isIterationEnabled() {\r
-               return iterationEnabled;\r
-       }\r
-\r
-}\r
+package org.simantics.spreadsheet.graph;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.binding.Binding;
+import org.simantics.databoard.binding.mutable.Variant;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.simulator.toolkit.StandardNodeManagerSupport;
+import org.simantics.simulator.variable.exceptions.NodeManagerException;
+import org.simantics.spreadsheet.graph.formula.SpreadsheetEvaluationEnvironment;
+import org.simantics.spreadsheet.graph.synchronization.LineNodeUpdater;
+import org.simantics.spreadsheet.graph.synchronization.LineUpdater;
+import org.simantics.spreadsheet.graph.synchronization.NullUpdater;
+import org.simantics.spreadsheet.graph.synchronization.SheetLineComponent;
+import org.simantics.spreadsheet.graph.synchronization.StyleUpdater;
+import org.simantics.structural.synchronization.base.ComponentFactory;
+import org.simantics.structural.synchronization.base.MappingBase;
+import org.simantics.structural.synchronization.base.ModuleUpdaterBase;
+import org.simantics.structural.synchronization.base.ModuleUpdaterFactoryBase;
+import org.simantics.structural.synchronization.base.Solver;
+import org.simantics.structural.synchronization.base.SolverNameUtil;
+
+import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
+import it.unimi.dsi.fastutil.longs.AbstractLongList;
+import it.unimi.dsi.fastutil.longs.AbstractLongSet;
+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.longs.LongArraySet;
+import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet;
+
+public class SpreadsheetBook implements StandardNodeManagerSupport<SheetNode>, SpreadsheetElement<SpreadsheetElement, SpreadsheetElement>, Serializable, SheetNode<SpreadsheetEngine, SheetNode>, Solver, SolverNameUtil, ComponentFactory<SheetLineComponent>, ModuleUpdaterFactoryBase<SheetLineComponent> {
+
+       private static final long serialVersionUID = 7417208688311691396L;
+       
+       public Serializable NotAvailableError = new Serializable() {};
+       
+       public Long2ObjectOpenHashMap<AbstractLongSet> referenceMap = new Long2ObjectOpenHashMap<>();
+       
+       private Int2ObjectArrayMap<SpreadsheetStyle> styles = new Int2ObjectArrayMap<>();
+//     public ObjectArrayList<SpreadsheetStyle> styles = new ObjectArrayList<SpreadsheetStyle>();
+       public ArrayList<SpreadsheetEngine> sheets = new ArrayList<SpreadsheetEngine>();
+       
+       private SpreadsheetMapping mapping;
+       
+       
+       private int idCounter = 1;
+       
+       public SpreadsheetBook() {
+               getNewId(this);
+               mapping = new SpreadsheetMapping(new SheetLineComponent(""));
+       }
+       
+       public Map<Integer, SpreadsheetElement> children = new HashMap<>();
+
+       private boolean iterationEnabled;
+
+       public int getNewId(SpreadsheetElement element) {
+               int result = idCounter++;
+               children.put(result, element);
+               return result; 
+       }
+       
+       public long getEngineIndex(SpreadsheetEngine engine) {
+               for(int i=0;i<sheets.size();i++)
+                       if(sheets.get(i) == engine) return i;
+               throw new IllegalStateException("Did not find sheet " + engine.getName());
+       }
+       
+       public void registerReferences(long cell, AbstractLongList refs) {
+               for(int i=0;i<refs.size();i++) {
+                       long key = refs.getLong(i);
+                       AbstractLongSet set = referenceMap.get(key);
+                       if(set == null) {
+                               set = new LongArraySet();
+                               referenceMap.put(key, set);
+                       }
+                       if(set.size() == 5) {
+                               AbstractLongSet newSet = new LongLinkedOpenHashSet();
+                               newSet.addAll(set);
+                               set = newSet;
+                               referenceMap.put(key, set);
+                       }
+                       set.add(cell);
+               }
+       }
+       
+       @Override
+       public Binding getEngineBinding(SheetNode node) throws NodeManagerException {
+               Object value = getEngineValue(node);
+               if(value instanceof Variant) return Bindings.VARIANT;
+               if(value instanceof String) return Bindings.STRING;
+               if(value instanceof Boolean) return Bindings.BOOLEAN;
+               else return Bindings.VOID;
+               
+       }
+       
+       @Override
+       public Object getEngineValue(SheetNode node) {
+               if(node instanceof SpreadsheetCellContent) {
+                       try {
+                               SpreadsheetCellContent scc = (SpreadsheetCellContent)node;
+                               Object content = scc.cell.evaluate(SpreadsheetEvaluationEnvironment.getInstance(this));
+                               if(content == null) return Variant.ofInstance("");
+                               if(content instanceof Variant) return content;
+                               else return Variant.ofInstance(content);
+                       } catch (Throwable t) {
+                               t.printStackTrace();
+                               return Variant.ofInstance(t.toString());
+                       }
+               } else if (node instanceof SpreadsheetCellContentExpression) {
+                       SpreadsheetCellContentExpression scce = (SpreadsheetCellContentExpression)node;
+                       if (scce.cell.content instanceof SpreadsheetFormula) {
+                       SpreadsheetFormula formula = (SpreadsheetFormula)scce.cell.content; 
+                       return formula.expression;
+                       } else if (scce.cell.content instanceof SpreadsheetSCLConstant) {
+                           SpreadsheetSCLConstant sclConstant = (SpreadsheetSCLConstant) scce.cell.content;
+                           return "=" + sclConstant.expression;
+                       } else {
+                           System.out.println("Broken SpreadsheetCellContentExpression possibly due to overwriting an existing expression with a constant or something else (current content is " + scce.cell.content + ")");
+                           if (scce.cell.content instanceof Variant) {
+                               return scce.cell.content;
+                           } else {
+                               return Variant.ofInstance(scce.cell.content);
+                           }
+                       }
+               } else if (node instanceof SpreadsheetTypeNode) {
+                       SpreadsheetTypeNode stn = (SpreadsheetTypeNode)node;
+                       return stn.uri;
+               } else if (node instanceof SpreadsheetCellStyle) {
+                   int styleId = ((SpreadsheetCellStyle) node).cell.style;
+                   SpreadsheetStyle style = getStyle(styleId);
+                   if (style == null) {
+                       style = SpreadsheetStyle.empty();
+                       if (styleId != style.getStyleId())
+                           new Exception("different style ids!" + styleId + "  " + style.getStyleId()).printStackTrace();
+                       addStyle(style);
+                   }
+                   return style;
+               } else if (node instanceof SpreadsheetCellEditable) {
+                   boolean editable = ((SpreadsheetCellEditable) node).editable();
+                   return editable;
+               }
+               return null;
+       }
+
+       @Override
+       public void setEngineValue(SheetNode node, Object value) {
+       }
+
+       @Override
+       public String getName(SheetNode node) {
+               return node.getName();
+       }
+
+       @Override
+       public Map<String, SheetNode> getChildren(SheetNode node) {
+               return node.getChildren();
+       }
+
+       @Override
+       public Map<String, SheetNode> getProperties(SheetNode node) {
+               return node.getProperties();
+       }
+
+       @Override
+       public String getName() {
+               return "";
+       }
+
+       @Override
+       public Map<String, SpreadsheetEngine> getChildren() {
+               Map<String,SpreadsheetEngine> result = new HashMap<String,SpreadsheetEngine>();
+               for(SpreadsheetEngine engine : sheets)
+                       result.put(engine.getName(), engine);
+               return result;
+       }
+
+       @Override
+       public Map<String, SheetNode> getProperties() {
+               return Collections.emptyMap();
+       }
+       
+       public SpreadsheetCell get(String sheet, int row, int column) {
+               SpreadsheetEngine engine = getEngine(sheet);
+               if(engine == null) return null;
+               SpreadsheetLine line = engine.getLine(row);
+               if(line == null) return null;
+               if(line.cells.size() <= column) return null;
+               return line.cells.get(column);
+       }
+
+       public SpreadsheetCell get(SpreadsheetEngine engine, int row, int column) {
+               SpreadsheetLine line = engine.getLine(row);
+               if(line == null) return null;
+               if(line.cells.size() <= column) return null;
+               return line.cells.get(column);
+       }
+
+       public SpreadsheetEngine getEngine(String sheet) {
+               for(SpreadsheetEngine engine : sheets)
+                       if(sheet.equals(engine.getName())) return engine;
+               return null;
+       }
+
+       @Override
+       public ModuleUpdaterBase<SheetLineComponent> createUpdater(String id) throws DatabaseException {
+               if("http://www.simantics.org/Spreadsheet-1.2/Line".equals(id))
+                       return new LineUpdater(id);
+               else if("http://www.simantics.org/Spreadsheet-1.2/LineNode".equals(id))
+                       return new LineNodeUpdater(id);
+               else if ("http://www.simantics.org/Spreadsheet-1.2/Style".equals(id))
+                   return new StyleUpdater(id);
+               else if("http://www.simantics.org/Spreadsheet-1.2/Lines".equals(id))
+                       return new NullUpdater(id);
+               else if("http://www.simantics.org/Spreadsheet-1.2/Spreadsheet".equals(id))
+                       return new NullUpdater(id);
+               else if("http://www.simantics.org/Spreadsheet-1.2/Book".equals(id))
+                       return new NullUpdater(id);
+               else
+                       throw new IllegalStateException("createUpdater " + id);
+       }
+
+       @Override
+       public SheetLineComponent create(String uid) {
+               return new SheetLineComponent(uid);
+       }
+
+       @Override
+       public String getFreshName(String parentName, String name) {
+               return parentName + "/" + name;
+       }
+
+       @Override
+       public String ensureNameIsVariationOf(String parentName, int id, String name) {
+           if (parentName.isEmpty())
+               return name;
+               return parentName + "/" + name;
+       }
+
+       final static int COMP_ROOT_POS = "COMP_ROOT/".length();
+       
+       @Override
+       public int getId(String name) {
+               
+               if("COMP_ROOT".equals(name)) return 1;
+
+               String path = name.substring(COMP_ROOT_POS);
+               String[] parts = path.split("/");
+               Object o = resolve(parts, 0);
+               if(o instanceof SpreadsheetLines) {
+                       return ((SpreadsheetLines)o).getId();
+               } else if(o instanceof SpreadsheetLine) {
+                       return ((SpreadsheetLine)o).getId();
+               } else if(o instanceof SpreadsheetEngine) {
+                       return ((SpreadsheetEngine)o).getId();
+               } else if (o instanceof SpreadsheetStyle) {
+                   return ((SpreadsheetStyle) o).getId();
+               }
+               
+               throw new IllegalStateException("Resolved object for parts " + Arrays.toString(parts) + " is not the right type! It is " + o);
+               
+       }
+       
+       Object resolve(String[] parts, int index) {
+               String part = parts[index];
+               if (part.startsWith("Style")) {
+                   for (SpreadsheetStyle style : styles.values()) {
+                       if (style.name.equals(part)) {
+                           return style;
+                       }
+                   }
+               }
+               SpreadsheetEngine engine = getEngine(part);
+               if(engine == null) return 0;
+               if(index == parts.length-1) return engine;
+               else return engine.resolve(parts, index+1);
+       }
+
+       @Override
+       public String getName(int id) {
+               if(id == -2) return "http://www.simantics.org/Spreadsheet-1.2/Book";
+               else if(id == -3) return "http://www.simantics.org/Spreadsheet-1.2/Spreadsheet";
+               else if(id == -4) return "http://www.simantics.org/Spreadsheet-1.2/Lines";
+               else if(id == -5)
+                   return "http://www.simantics.org/Spreadsheet-1.2/LineNode";
+               else if (id == -6)
+                   return "http://www.simantics.org/Spreadsheet-1.2/Line";
+               else if(id == -7)
+                   return "http://www.simantics.org/Spreadsheet-1.2/Style";
+               else return "" + id;
+       }
+
+       @Override
+       public int getModuleType(int id) {
+               Serializable s = children.get(id);
+               if(s instanceof SpreadsheetBook) return -2;
+               else if(s instanceof SpreadsheetEngine) return -3;
+               else if(s instanceof SpreadsheetLines) {
+                       if("Lines".equals(((SpreadsheetLines) s).getName()))
+                               return -4;
+                       else
+                               return -5;
+               }
+               else if(s instanceof SpreadsheetLine)
+                   return -6;
+               else if (s instanceof SpreadsheetStyle)
+                   return -7;
+               else throw new IllegalStateException();
+       }
+
+       @Override
+       public void remove(int id) {
+           
+           SpreadsheetElement child = children.get(id);
+           Optional<SpreadsheetElement> parent = child.getParent();
+           
+           if (parent.isPresent()) {
+               parent.get().remove(child);
+               children.remove(id);
+           }
+       }
+
+       @Override
+       public void addSubprocess(String name, String subprocessType) {
+               ensureSubprocess(name);
+       }
+       
+       public <T> T ensureSubprocess(String name) {
+               String[] parts = name.split("/");
+               if(parts.length == 2) {
+                       SpreadsheetEngine engine = getEngine(parts[1]);
+                       if(engine == null) {
+                               engine = new SpreadsheetEngine(this, parts[1]);
+                               sheets.add(engine);
+                       }
+                       return (T)engine;
+               } else if (parts.length > 2) {
+                       SpreadsheetEngine engine = getEngine(parts[1]);
+                       return (T)engine.ensureSubprocess(parts, 2);
+               }
+               throw new IllegalStateException();
+       }
+       
+
+       @Override
+       public void includeSubprocess(String parentName, String subprocessName) {
+               // Nop
+       }
+
+       @Override
+       public <T> T getConcreteSolver() {
+               return (T)this;
+       }
+       
+       @Override
+       public void accept(SpreadsheetVisitor v) {
+               v.visit(this);
+       }
+       
+       //Recursively find all SpreadsheetCells, invalidate them and return them all as a set
+       public Set<SpreadsheetCell> invalidate(SpreadsheetCell cell) {
+               Set<SpreadsheetCell> result = new HashSet<>();
+               result.add(cell);
+               cell.invalidate();
+               long refKey = cell.makeReferenceKey();
+               AbstractLongSet refs = referenceMap.remove(refKey);
+               if(refs == null) return result;
+               for(long ref : refs) {
+                       long sheet = ref >> 40;
+                       long row = (ref >> 20) & 0xFFFFF;
+                       long col = (ref) & 0xFFFFF;
+                       SpreadsheetCell referer = get(sheets.get((int)sheet), (int)row, (int)col);
+                       result.addAll(invalidate(referer));
+               }
+               return result;
+       }
+       
+       @Deprecated
+       public List<SpreadsheetCell> invalidateShallow(SpreadsheetCell cell) {
+               ArrayList<SpreadsheetCell> result = new ArrayList<>();
+               result.add(cell);
+               cell.invalidate();
+               long refKey = cell.makeReferenceKey();
+               AbstractLongSet refs = referenceMap.remove(refKey);
+               if(refs == null) return result;
+               for(long ref : refs) {
+                       long sheet = ref >> 40;
+                       long row = (ref >> 20) & 0xFFFFF;
+                       long col = (ref) & 0xFFFFF;
+                       SpreadsheetCell referer = get(sheets.get((int)sheet), (int)row, (int)col);
+                       invalidate(referer);
+                       result.add(referer);
+               }
+               return result;
+       }
+
+    public void addStyle(SpreadsheetStyle style) {
+        if (style.name == null) {
+            new Exception("Trying to add style to book without name!!").printStackTrace();
+            return;
+        }
+        style.setSynchronizationId(getNewId(style));
+        styles.put(style.getStyleId(), style);
+    }
+
+    public SpreadsheetStyle getStyle(int styleId) {
+        return styles.get(styleId);
+    }
+
+    public MappingBase<SheetLineComponent> getMapping() {
+        return mapping;
+    }
+
+    @Override
+    public Optional<SpreadsheetElement> getParent() {
+        return Optional.empty();
+    }
+
+    @Override
+    public Collection<SpreadsheetElement> getSpreadsheetChildren() {
+        return children.values();
+    }
+
+    @Override
+    public void remove(SpreadsheetElement child) {
+        // TODO Auto-generated method stub
+        
+    }
+
+       public void setIterationEnabled(boolean value) {
+               this.iterationEnabled = value;
+       }
+       
+       public boolean isIterationEnabled() {
+               return iterationEnabled;
+       }
+
+}