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