]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/SpreadsheetBook.java
Added editable unit for derived properties
[simantics/platform.git] / bundles / org.simantics.spreadsheet.graph / src / org / simantics / spreadsheet / graph / SpreadsheetBook.java
1 package org.simantics.spreadsheet.graph;
2
3 import java.io.Serializable;
4 import java.util.ArrayList;
5 import java.util.Arrays;
6 import java.util.Collection;
7 import java.util.Collections;
8 import java.util.HashMap;
9 import java.util.HashSet;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Optional;
13 import java.util.Set;
14
15 import org.simantics.databoard.Bindings;
16 import org.simantics.databoard.binding.Binding;
17 import org.simantics.databoard.binding.mutable.Variant;
18 import org.simantics.db.exception.DatabaseException;
19 import org.simantics.simulator.toolkit.StandardNodeManagerSupport;
20 import org.simantics.simulator.variable.exceptions.NodeManagerException;
21 import org.simantics.spreadsheet.graph.formula.SpreadsheetEvaluationEnvironment;
22 import org.simantics.spreadsheet.graph.synchronization.LineNodeUpdater;
23 import org.simantics.spreadsheet.graph.synchronization.LineUpdater;
24 import org.simantics.spreadsheet.graph.synchronization.NullUpdater;
25 import org.simantics.spreadsheet.graph.synchronization.SheetLineComponent;
26 import org.simantics.spreadsheet.graph.synchronization.StyleUpdater;
27 import org.simantics.structural.synchronization.base.ComponentFactory;
28 import org.simantics.structural.synchronization.base.MappingBase;
29 import org.simantics.structural.synchronization.base.ModuleUpdaterBase;
30 import org.simantics.structural.synchronization.base.ModuleUpdaterFactoryBase;
31 import org.simantics.structural.synchronization.base.Solver;
32 import org.simantics.structural.synchronization.base.SolverNameUtil;
33
34 import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
35 import it.unimi.dsi.fastutil.longs.AbstractLongList;
36 import it.unimi.dsi.fastutil.longs.AbstractLongSet;
37 import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
38 import it.unimi.dsi.fastutil.longs.LongArraySet;
39 import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet;
40
41 public class SpreadsheetBook implements StandardNodeManagerSupport<SheetNode>, SpreadsheetElement<SpreadsheetElement, SpreadsheetElement>, Serializable, SheetNode<SpreadsheetEngine, SheetNode>, Solver, SolverNameUtil, ComponentFactory<SheetLineComponent>, ModuleUpdaterFactoryBase<SheetLineComponent> {
42
43         private static final long serialVersionUID = 7417208688311691396L;
44         
45         public Serializable NotAvailableError = new Serializable() {
46                 private static final long serialVersionUID = 2535371785498129460L;
47         };
48         
49         public Long2ObjectOpenHashMap<AbstractLongSet> referenceMap = new Long2ObjectOpenHashMap<>();
50         
51         private Int2ObjectArrayMap<SpreadsheetStyle> styles = new Int2ObjectArrayMap<>();
52 //      public ObjectArrayList<SpreadsheetStyle> styles = new ObjectArrayList<SpreadsheetStyle>();
53         public ArrayList<SpreadsheetEngine> sheets = new ArrayList<SpreadsheetEngine>();
54         
55         private SpreadsheetMapping mapping;
56         
57         
58         private int idCounter = 1;
59         
60         public SpreadsheetBook() {
61                 getNewId(this);
62                 mapping = new SpreadsheetMapping(new SheetLineComponent(""));
63         }
64         
65         public Map<Integer, SpreadsheetElement> children = new HashMap<>();
66
67         private boolean iterationEnabled;
68
69         public int getNewId(SpreadsheetElement element) {
70                 int result = idCounter++;
71                 children.put(result, element);
72                 return result; 
73         }
74         
75         public long getEngineIndex(SpreadsheetEngine engine) {
76                 for(int i=0;i<sheets.size();i++)
77                         if(sheets.get(i) == engine) return i;
78                 throw new IllegalStateException("Did not find sheet " + engine.getName());
79         }
80         
81         public void registerReferences(long cell, AbstractLongList refs) {
82                 for(int i=0;i<refs.size();i++) {
83                         long key = refs.getLong(i);
84                         AbstractLongSet set = referenceMap.get(key);
85                         if(set == null) {
86                                 set = new LongArraySet();
87                                 referenceMap.put(key, set);
88                         }
89                         if(set.size() == 5) {
90                                 AbstractLongSet newSet = new LongLinkedOpenHashSet();
91                                 newSet.addAll(set);
92                                 set = newSet;
93                                 referenceMap.put(key, set);
94                         }
95                         set.add(cell);
96                 }
97         }
98         
99         @Override
100         public Binding getEngineBinding(SheetNode node) throws NodeManagerException {
101                 Object value = getEngineValue(node);
102                 if(value instanceof Variant) return Bindings.VARIANT;
103                 if(value instanceof String) return Bindings.STRING;
104                 if(value instanceof Boolean) return Bindings.BOOLEAN;
105                 else return Bindings.VOID;
106                 
107         }
108         
109         @Override
110         public Object getEngineValue(SheetNode node) {
111                 if(node instanceof SpreadsheetCellContent) {
112                         try {
113                                 SpreadsheetCellContent scc = (SpreadsheetCellContent)node;
114                                 Object content = scc.cell.evaluate(SpreadsheetEvaluationEnvironment.getInstance(this));
115                                 if(content == null) return Variant.ofInstance("");
116                                 if(content instanceof Variant) return content;
117                                 else return Variant.ofInstance(content);
118                         } catch (Throwable t) {
119                                 t.printStackTrace();
120                                 return Variant.ofInstance(t.toString());
121                         }
122                 } else if (node instanceof SpreadsheetCellContentExpression) {
123                         SpreadsheetCellContentExpression scce = (SpreadsheetCellContentExpression)node;
124                         if (scce.cell.content instanceof SpreadsheetFormula) {
125                         SpreadsheetFormula formula = (SpreadsheetFormula)scce.cell.content; 
126                         return formula.expression;
127                         } else if (scce.cell.content instanceof SpreadsheetSCLConstant) {
128                             SpreadsheetSCLConstant sclConstant = (SpreadsheetSCLConstant) scce.cell.content;
129                             return "=" + sclConstant.expression;
130                         } else {
131                             System.out.println("Broken SpreadsheetCellContentExpression possibly due to overwriting an existing expression with a constant or something else (current content is " + scce.cell.content + ")");
132                             if (scce.cell.content instanceof Variant) {
133                                 return scce.cell.content;
134                             } else {
135                                 return Variant.ofInstance(scce.cell.content);
136                             }
137                         }
138                 } else if (node instanceof SpreadsheetTypeNode) {
139                         SpreadsheetTypeNode stn = (SpreadsheetTypeNode)node;
140                         return stn.uri;
141                 } else if (node instanceof SpreadsheetCellStyle) {
142                     int styleId = ((SpreadsheetCellStyle) node).cell.style;
143                     SpreadsheetStyle style = getStyle(styleId);
144                     if (style == null) {
145                         style = SpreadsheetStyle.empty();
146                         if (styleId != style.getStyleId())
147                             new Exception("different style ids!" + styleId + "  " + style.getStyleId()).printStackTrace();
148                         addStyle(style);
149                     }
150                     return style;
151                 } else if (node instanceof SpreadsheetCellEditable) {
152                     boolean editable = ((SpreadsheetCellEditable) node).editable();
153                     return editable;
154                 }
155                 return null;
156         }
157
158         @Override
159         public void setEngineValue(SheetNode node, Object value) {
160         }
161
162         @Override
163         public String getName(SheetNode node) {
164                 return node.getName();
165         }
166
167         @Override
168         public Map<String, SheetNode> getChildren(SheetNode node) {
169                 return node.getChildren();
170         }
171
172         @Override
173         public Map<String, SheetNode> getProperties(SheetNode node) {
174                 return node.getProperties();
175         }
176
177         @Override
178         public String getName() {
179                 return "";
180         }
181
182         @Override
183         public Map<String, SpreadsheetEngine> getChildren() {
184                 Map<String,SpreadsheetEngine> result = new HashMap<String,SpreadsheetEngine>();
185                 for(SpreadsheetEngine engine : sheets)
186                         result.put(engine.getName(), engine);
187                 return result;
188         }
189
190         @Override
191         public Map<String, SheetNode> getProperties() {
192                 return Collections.emptyMap();
193         }
194         
195         public SpreadsheetCell get(String sheet, int row, int column) {
196                 SpreadsheetEngine engine = getEngine(sheet);
197                 if(engine == null) return null;
198                 SpreadsheetLine line = engine.getLine(row);
199                 if(line == null) return null;
200                 if(line.cells.size() <= column) return null;
201                 return line.cells.get(column);
202         }
203
204         public SpreadsheetCell get(SpreadsheetEngine engine, int row, int column) {
205                 SpreadsheetLine line = engine.getLine(row);
206                 if(line == null) return null;
207                 if(line.cells.size() <= column) return null;
208                 return line.cells.get(column);
209         }
210
211         public SpreadsheetEngine getEngine(String sheet) {
212                 for(SpreadsheetEngine engine : sheets)
213                         if(sheet.equals(engine.getName())) return engine;
214                 return null;
215         }
216
217         @Override
218         public ModuleUpdaterBase<SheetLineComponent> createUpdater(String id) throws DatabaseException {
219                 if("http://www.simantics.org/Spreadsheet-1.2/Line".equals(id))
220                         return new LineUpdater(id);
221                 else if("http://www.simantics.org/Spreadsheet-1.2/LineNode".equals(id))
222                         return new LineNodeUpdater(id);
223                 else if ("http://www.simantics.org/Spreadsheet-1.2/Style".equals(id))
224                     return new StyleUpdater(id);
225                 else if("http://www.simantics.org/Spreadsheet-1.2/Lines".equals(id))
226                         return new NullUpdater(id);
227                 else if("http://www.simantics.org/Spreadsheet-1.2/Spreadsheet".equals(id))
228                         return new NullUpdater(id);
229                 else if("http://www.simantics.org/Spreadsheet-1.2/Book".equals(id))
230                         return new NullUpdater(id);
231                 else
232                         throw new IllegalStateException("createUpdater " + id);
233         }
234
235         @Override
236         public SheetLineComponent create(String uid) {
237                 return new SheetLineComponent(uid);
238         }
239
240         @Override
241         public String getFreshName(String parentName, String name) {
242                 return parentName + "/" + name;
243         }
244
245         @Override
246         public String ensureNameIsVariationOf(String parentName, int id, String name) {
247             if (parentName.isEmpty())
248                 return name;
249                 return parentName + "/" + name;
250         }
251
252         final static int COMP_ROOT_POS = "COMP_ROOT/".length();
253         
254         @Override
255         public int getId(String name) {
256                 
257                 if("COMP_ROOT".equals(name)) return 1;
258
259                 String path = name.substring(COMP_ROOT_POS);
260                 String[] parts = path.split("/");
261                 Object o = resolve(parts, 0);
262                 if(o instanceof SpreadsheetLines) {
263                         return ((SpreadsheetLines)o).getId();
264                 } else if(o instanceof SpreadsheetLine) {
265                         return ((SpreadsheetLine)o).getId();
266                 } else if(o instanceof SpreadsheetEngine) {
267                         return ((SpreadsheetEngine)o).getId();
268                 } else if (o instanceof SpreadsheetStyle) {
269                     return ((SpreadsheetStyle) o).getId();
270                 }
271                 
272                 throw new IllegalStateException("Resolved object for parts " + Arrays.toString(parts) + " is not the right type! It is " + o);
273                 
274         }
275         
276         Object resolve(String[] parts, int index) {
277                 String part = parts[index];
278                 if (part.startsWith("Style")) {
279                     for (SpreadsheetStyle style : styles.values()) {
280                         if (style.name.equals(part)) {
281                             return style;
282                         }
283                     }
284                 }
285                 SpreadsheetEngine engine = getEngine(part);
286                 if(engine == null) return 0;
287                 if(index == parts.length-1) return engine;
288                 else return engine.resolve(parts, index+1);
289         }
290
291         @Override
292         public String getName(int id) {
293                 if(id == -2) return "http://www.simantics.org/Spreadsheet-1.2/Book";
294                 else if(id == -3) return "http://www.simantics.org/Spreadsheet-1.2/Spreadsheet";
295                 else if(id == -4) return "http://www.simantics.org/Spreadsheet-1.2/Lines";
296                 else if(id == -5)
297                     return "http://www.simantics.org/Spreadsheet-1.2/LineNode";
298                 else if (id == -6)
299                     return "http://www.simantics.org/Spreadsheet-1.2/Line";
300                 else if(id == -7)
301                     return "http://www.simantics.org/Spreadsheet-1.2/Style";
302                 else return "" + id;
303         }
304
305         @Override
306         public int getModuleType(int id) {
307                 Serializable s = children.get(id);
308                 if(s instanceof SpreadsheetBook) return -2;
309                 else if(s instanceof SpreadsheetEngine) return -3;
310                 else if(s instanceof SpreadsheetLines) {
311                         if("Lines".equals(((SpreadsheetLines) s).getName()))
312                                 return -4;
313                         else
314                                 return -5;
315                 }
316                 else if(s instanceof SpreadsheetLine)
317                     return -6;
318                 else if (s instanceof SpreadsheetStyle)
319                     return -7;
320                 else throw new IllegalStateException();
321         }
322
323         @Override
324         public void remove(int id) {
325             
326             SpreadsheetElement child = children.get(id);
327             Optional<SpreadsheetElement> parent = child.getParent();
328             
329             if (parent.isPresent()) {
330                 parent.get().remove(child);
331                 children.remove(id);
332             }
333         }
334
335         @Override
336         public void addSubprocess(String name, String subprocessType) {
337                 ensureSubprocess(name);
338         }
339         
340         public <T> T ensureSubprocess(String name) {
341                 String[] parts = name.split("/");
342                 if(parts.length == 2) {
343                         SpreadsheetEngine engine = getEngine(parts[1]);
344                         if(engine == null) {
345                                 engine = new SpreadsheetEngine(this, parts[1]);
346                                 sheets.add(engine);
347                         }
348                         return (T)engine;
349                 } else if (parts.length > 2) {
350                         SpreadsheetEngine engine = getEngine(parts[1]);
351                         return (T)engine.ensureSubprocess(parts, 2);
352                 }
353                 throw new IllegalStateException();
354         }
355         
356
357         @Override
358         public void includeSubprocess(String parentName, String subprocessName) {
359                 // Nop
360         }
361
362         @Override
363         public <T> T getConcreteSolver() {
364                 return (T)this;
365         }
366         
367         @Override
368         public void accept(SpreadsheetVisitor v) {
369                 v.visit(this);
370         }
371         
372         //Recursively find all SpreadsheetCells, invalidate them and return them all as a set
373         public Set<SpreadsheetCell> invalidate(SpreadsheetCell cell) {
374                 Set<SpreadsheetCell> result = new HashSet<>();
375                 result.add(cell);
376                 cell.invalidate();
377                 long refKey = cell.makeReferenceKey();
378                 AbstractLongSet refs = referenceMap.remove(refKey);
379                 if(refs == null) return result;
380                 for(long ref : refs) {
381                         long sheet = ref >> 40;
382                         long row = (ref >> 20) & 0xFFFFF;
383                         long col = (ref) & 0xFFFFF;
384                         SpreadsheetCell referer = get(sheets.get((int)sheet), (int)row, (int)col);
385                         result.addAll(invalidate(referer));
386                 }
387                 return result;
388         }
389         
390         @Deprecated
391         public List<SpreadsheetCell> invalidateShallow(SpreadsheetCell cell) {
392                 ArrayList<SpreadsheetCell> result = new ArrayList<>();
393                 result.add(cell);
394                 cell.invalidate();
395                 long refKey = cell.makeReferenceKey();
396                 AbstractLongSet refs = referenceMap.remove(refKey);
397                 if(refs == null) return result;
398                 for(long ref : refs) {
399                         long sheet = ref >> 40;
400                         long row = (ref >> 20) & 0xFFFFF;
401                         long col = (ref) & 0xFFFFF;
402                         SpreadsheetCell referer = get(sheets.get((int)sheet), (int)row, (int)col);
403                         invalidate(referer);
404                         result.add(referer);
405                 }
406                 return result;
407         }
408
409     public void addStyle(SpreadsheetStyle style) {
410         if (style.name == null) {
411             new Exception("Trying to add style to book without name!!").printStackTrace();
412             return;
413         }
414         style.setSynchronizationId(getNewId(style));
415         styles.put(style.getStyleId(), style);
416     }
417
418     public SpreadsheetStyle getStyle(int styleId) {
419         return styles.get(styleId);
420     }
421
422     public MappingBase<SheetLineComponent> getMapping() {
423         return mapping;
424     }
425
426     @Override
427     public Optional<SpreadsheetElement> getParent() {
428         return Optional.empty();
429     }
430
431     @Override
432     public Collection<SpreadsheetElement> getSpreadsheetChildren() {
433         return children.values();
434     }
435
436     @Override
437     public void remove(SpreadsheetElement child) {
438         // TODO Auto-generated method stub
439         
440     }
441
442         public void setIterationEnabled(boolean value) {
443                 this.iterationEnabled = value;
444         }
445         
446         public boolean isIterationEnabled() {
447                 return iterationEnabled;
448         }
449
450 }