1 package org.simantics.spreadsheet.graph;
\r
3 import java.io.Serializable;
\r
4 import java.util.ArrayList;
\r
5 import java.util.Arrays;
\r
6 import java.util.Collection;
\r
7 import java.util.Collections;
\r
8 import java.util.HashMap;
\r
9 import java.util.List;
\r
10 import java.util.Map;
\r
11 import java.util.Optional;
\r
13 import org.simantics.databoard.binding.mutable.Variant;
\r
14 import org.simantics.db.exception.DatabaseException;
\r
15 import org.simantics.db.layer0.StandardEngine;
\r
16 import org.simantics.spreadsheet.graph.formula.SpreadsheetEvaluationEnvironment;
\r
17 import org.simantics.spreadsheet.graph.synchronization.LineNodeUpdater;
\r
18 import org.simantics.spreadsheet.graph.synchronization.LineUpdater;
\r
19 import org.simantics.spreadsheet.graph.synchronization.NullUpdater;
\r
20 import org.simantics.spreadsheet.graph.synchronization.SheetLineComponent;
\r
21 import org.simantics.spreadsheet.graph.synchronization.StyleUpdater;
\r
22 import org.simantics.structural.synchronization.base.ComponentFactory;
\r
23 import org.simantics.structural.synchronization.base.MappingBase;
\r
24 import org.simantics.structural.synchronization.base.ModuleUpdaterBase;
\r
25 import org.simantics.structural.synchronization.base.ModuleUpdaterFactoryBase;
\r
26 import org.simantics.structural.synchronization.base.Solver;
\r
27 import org.simantics.structural.synchronization.base.SolverNameUtil;
\r
29 import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
\r
30 import it.unimi.dsi.fastutil.longs.AbstractLongList;
\r
31 import it.unimi.dsi.fastutil.longs.AbstractLongSet;
\r
32 import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
\r
33 import it.unimi.dsi.fastutil.longs.LongArraySet;
\r
34 import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet;
\r
36 public class SpreadsheetBook implements SpreadsheetElement<SpreadsheetElement, SpreadsheetElement>, StandardEngine<SheetNode>, Serializable, SheetNode<SpreadsheetEngine, SheetNode>, Solver, SolverNameUtil, ComponentFactory<SheetLineComponent>, ModuleUpdaterFactoryBase<SheetLineComponent> {
\r
38 private static final long serialVersionUID = 7417208688311691396L;
\r
40 public Serializable NotAvailableError = new Serializable() {};
\r
42 public Long2ObjectOpenHashMap<AbstractLongSet> referenceMap = new Long2ObjectOpenHashMap<>();
\r
44 private Int2ObjectArrayMap<SpreadsheetStyle> styles = new Int2ObjectArrayMap<>();
\r
45 // public ObjectArrayList<SpreadsheetStyle> styles = new ObjectArrayList<SpreadsheetStyle>();
\r
46 public ArrayList<SpreadsheetEngine> sheets = new ArrayList<SpreadsheetEngine>();
\r
48 private SpreadsheetMapping mapping;
\r
51 private int idCounter = 1;
\r
53 public SpreadsheetBook() {
\r
55 mapping = new SpreadsheetMapping(new SheetLineComponent(""));
\r
58 public Map<Integer, SpreadsheetElement> children = new HashMap<>();
\r
60 public int getNewId(SpreadsheetElement element) {
\r
61 int result = idCounter++;
\r
62 children.put(result, element);
\r
66 public long getEngineIndex(SpreadsheetEngine engine) {
\r
67 for(int i=0;i<sheets.size();i++)
\r
68 if(sheets.get(i) == engine) return i;
\r
69 throw new IllegalStateException("Did not find sheet " + engine.getName());
\r
72 public void registerReferences(long cell, AbstractLongList refs) {
\r
73 for(int i=0;i<refs.size();i++) {
\r
74 long key = refs.getLong(i);
\r
75 AbstractLongSet set = referenceMap.get(key);
\r
77 set = new LongArraySet();
\r
78 referenceMap.put(key, set);
\r
80 if(set.size() == 5) {
\r
81 AbstractLongSet newSet = new LongLinkedOpenHashSet();
\r
84 referenceMap.put(key, set);
\r
91 public Object getValue(SheetNode node) {
\r
92 if(node instanceof SpreadsheetCellContent) {
\r
94 SpreadsheetCellContent scc = (SpreadsheetCellContent)node;
\r
95 Object content = scc.cell.evaluate(SpreadsheetEvaluationEnvironment.getInstance(this));
\r
96 if(content == null) return Variant.ofInstance("");
\r
97 if(content instanceof Variant) return content;
\r
98 else return Variant.ofInstance(content);
\r
99 } catch (Throwable t) {
\r
100 t.printStackTrace();
\r
101 return Variant.ofInstance(t.toString());
\r
103 } else if (node instanceof SpreadsheetCellContentExpression) {
\r
104 SpreadsheetCellContentExpression scce = (SpreadsheetCellContentExpression)node;
\r
105 if (scce.cell.content instanceof SpreadsheetFormula) {
\r
106 SpreadsheetFormula formula = (SpreadsheetFormula)scce.cell.content;
\r
107 return formula.expression;
\r
108 } else if (scce.cell.content instanceof SpreadsheetSCLConstant) {
\r
109 SpreadsheetSCLConstant sclConstant = (SpreadsheetSCLConstant) scce.cell.content;
\r
110 return "=" + sclConstant.expression;
\r
112 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
113 if (scce.cell.content instanceof Variant) {
\r
114 return scce.cell.content;
\r
116 return Variant.ofInstance(scce.cell.content);
\r
119 } else if (node instanceof SpreadsheetTypeNode) {
\r
120 SpreadsheetTypeNode stn = (SpreadsheetTypeNode)node;
\r
122 } else if (node instanceof SpreadsheetCellStyle) {
\r
123 int styleId = ((SpreadsheetCellStyle) node).cell.style;
\r
124 SpreadsheetStyle style = getStyle(styleId);
\r
125 if (style == null) {
\r
126 style = SpreadsheetStyle.empty();
\r
127 if (styleId != style.getStyleId())
\r
128 new Exception("different style ids!" + styleId + " " + style.getStyleId()).printStackTrace();
\r
132 } else if (node instanceof SpreadsheetCellEditable) {
\r
133 boolean editable = ((SpreadsheetCellEditable) node).editable();
\r
140 public void setValue(SheetNode node, Object value) {
\r
144 public String getName(SheetNode node) {
\r
145 return node.getName();
\r
149 public Map<String, SheetNode> getChildren(SheetNode node) {
\r
150 return node.getChildren();
\r
154 public Map<String, SheetNode> getProperties(SheetNode node) {
\r
155 return node.getProperties();
\r
159 public String getName() {
\r
164 public Map<String, SpreadsheetEngine> getChildren() {
\r
165 Map<String,SpreadsheetEngine> result = new HashMap<String,SpreadsheetEngine>();
\r
166 for(SpreadsheetEngine engine : sheets)
\r
167 result.put(engine.getName(), engine);
\r
172 public Map<String, SheetNode> getProperties() {
\r
173 return Collections.emptyMap();
\r
176 public SpreadsheetCell get(String sheet, int row, int column) {
\r
177 SpreadsheetEngine engine = getEngine(sheet);
\r
178 if(engine == null) return null;
\r
179 SpreadsheetLine line = engine.getLine(row);
\r
180 if(line == null) return null;
\r
181 if(line.cells.size() <= column) return null;
\r
182 return line.cells.get(column);
\r
185 public SpreadsheetCell get(SpreadsheetEngine engine, int row, int column) {
\r
186 SpreadsheetLine line = engine.getLine(row);
\r
187 if(line == null) return null;
\r
188 if(line.cells.size() <= column) return null;
\r
189 return line.cells.get(column);
\r
192 public SpreadsheetEngine getEngine(String sheet) {
\r
193 for(SpreadsheetEngine engine : sheets)
\r
194 if(sheet.equals(engine.getName())) return engine;
\r
199 public ModuleUpdaterBase<SheetLineComponent> createUpdater(String id) throws DatabaseException {
\r
200 if("http://www.simantics.org/Spreadsheet-1.2/Line".equals(id))
\r
201 return new LineUpdater(id);
\r
202 else if("http://www.simantics.org/Spreadsheet-1.2/LineNode".equals(id))
\r
203 return new LineNodeUpdater(id);
\r
204 else if ("http://www.simantics.org/Spreadsheet-1.2/Style".equals(id))
\r
205 return new StyleUpdater(id);
\r
206 else if("http://www.simantics.org/Spreadsheet-1.2/Lines".equals(id))
\r
207 return new NullUpdater(id);
\r
208 else if("http://www.simantics.org/Spreadsheet-1.2/Spreadsheet".equals(id))
\r
209 return new NullUpdater(id);
\r
210 else if("http://www.simantics.org/Spreadsheet-1.2/Book".equals(id))
\r
211 return new NullUpdater(id);
\r
213 throw new IllegalStateException("createUpdater " + id);
\r
217 public SheetLineComponent create(String uid) {
\r
218 return new SheetLineComponent(uid);
\r
222 public String getFreshName(String parentName, String name) {
\r
223 return parentName + "/" + name;
\r
227 public String ensureNameIsVariationOf(String parentName, int id, String name) {
\r
228 if (parentName.isEmpty())
\r
230 return parentName + "/" + name;
\r
233 final static int COMP_ROOT_POS = "COMP_ROOT/".length();
\r
236 public int getId(String name) {
\r
238 if("COMP_ROOT".equals(name)) return 1;
\r
240 String path = name.substring(COMP_ROOT_POS);
\r
241 String[] parts = path.split("/");
\r
242 Object o = resolve(parts, 0);
\r
243 if(o instanceof SpreadsheetLines) {
\r
244 return ((SpreadsheetLines)o).getId();
\r
245 } else if(o instanceof SpreadsheetLine) {
\r
246 return ((SpreadsheetLine)o).getId();
\r
247 } else if(o instanceof SpreadsheetEngine) {
\r
248 return ((SpreadsheetEngine)o).getId();
\r
249 } else if (o instanceof SpreadsheetStyle) {
\r
250 return ((SpreadsheetStyle) o).getId();
\r
253 throw new IllegalStateException("Resolved object for parts " + Arrays.toString(parts) + " is not the right type! It is " + o);
\r
257 Object resolve(String[] parts, int index) {
\r
258 String part = parts[index];
\r
259 if (part.startsWith("Style")) {
\r
260 for (SpreadsheetStyle style : styles.values()) {
\r
261 if (style.name.equals(part)) {
\r
266 SpreadsheetEngine engine = getEngine(part);
\r
267 if(engine == null) return 0;
\r
268 if(index == parts.length-1) return engine;
\r
269 else return engine.resolve(parts, index+1);
\r
273 public String getName(int id) {
\r
274 if(id == -2) return "http://www.simantics.org/Spreadsheet-1.2/Book";
\r
275 else if(id == -3) return "http://www.simantics.org/Spreadsheet-1.2/Spreadsheet";
\r
276 else if(id == -4) return "http://www.simantics.org/Spreadsheet-1.2/Lines";
\r
278 return "http://www.simantics.org/Spreadsheet-1.2/LineNode";
\r
280 return "http://www.simantics.org/Spreadsheet-1.2/Line";
\r
282 return "http://www.simantics.org/Spreadsheet-1.2/Style";
\r
283 else return "" + id;
\r
287 public int getModuleType(int id) {
\r
288 Serializable s = children.get(id);
\r
289 if(s instanceof SpreadsheetBook) return -2;
\r
290 else if(s instanceof SpreadsheetEngine) return -3;
\r
291 else if(s instanceof SpreadsheetLines) {
\r
292 if("Lines".equals(((SpreadsheetLines) s).getName()))
\r
297 else if(s instanceof SpreadsheetLine)
\r
299 else if (s instanceof SpreadsheetStyle)
\r
301 else throw new IllegalStateException();
\r
305 public void remove(int id) {
\r
307 SpreadsheetElement child = children.get(id);
\r
308 Optional<SpreadsheetElement> parent = child.getParent();
\r
310 if (parent.isPresent()) {
\r
311 parent.get().remove(child);
\r
312 children.remove(id);
\r
317 public void addSubprocess(String name) {
\r
318 ensureSubprocess(name);
\r
321 public <T> T ensureSubprocess(String name) {
\r
322 String[] parts = name.split("/");
\r
323 if(parts.length == 2) {
\r
324 SpreadsheetEngine engine = getEngine(parts[1]);
\r
325 if(engine == null) {
\r
326 engine = new SpreadsheetEngine(this, parts[1]);
\r
327 sheets.add(engine);
\r
330 } else if (parts.length > 2) {
\r
331 SpreadsheetEngine engine = getEngine(parts[1]);
\r
332 return (T)engine.ensureSubprocess(parts, 2);
\r
334 throw new IllegalStateException();
\r
339 public void includeSubprocess(String parentName, String subprocessName) {
\r
344 public <T> T getConcreteSolver() {
\r
349 public void accept(SpreadsheetVisitor v) {
\r
353 public List<SpreadsheetCell> invalidate(SpreadsheetCell cell) {
\r
354 ArrayList<SpreadsheetCell> result = new ArrayList<>();
\r
357 long refKey = cell.makeReferenceKey();
\r
358 AbstractLongSet refs = referenceMap.remove(refKey);
\r
359 if(refs == null) return result;
\r
360 for(long ref : refs) {
\r
361 long sheet = ref >> 40;
\r
362 long row = (ref >> 20) & 0xFFFFF;
\r
363 long col = (ref) & 0xFFFFF;
\r
364 SpreadsheetCell referer = get(sheets.get((int)sheet), (int)row, (int)col);
\r
365 invalidate(referer);
\r
366 result.add(referer);
\r
371 public void addStyle(SpreadsheetStyle style) {
\r
372 if (style.name == null) {
\r
373 new Exception("Trying to add style to book without name!!").printStackTrace();
\r
376 style.setSynchronizationId(getNewId(style));
\r
377 styles.put(style.getStyleId(), style);
\r
380 public SpreadsheetStyle getStyle(int styleId) {
\r
381 return styles.get(styleId);
\r
384 public MappingBase<SheetLineComponent> getMapping() {
\r
389 public Optional<SpreadsheetElement> getParent() {
\r
390 return Optional.empty();
\r
394 public Collection<SpreadsheetElement> getSpreadsheetChildren() {
\r
395 return children.values();
\r
399 public void remove(SpreadsheetElement child) {
\r
400 // TODO Auto-generated method stub
\r