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