1 package org.simantics.spreadsheet.solver;
3 import java.util.Collections;
4 import java.util.HashMap;
7 import java.util.Optional;
9 import org.simantics.databoard.binding.mutable.Variant;
10 import org.simantics.spreadsheet.ExternalRef;
11 import org.simantics.spreadsheet.SpreadsheetCellStyle;
12 import org.simantics.spreadsheet.SpreadsheetVisitor;
13 import org.simantics.spreadsheet.Spreadsheets;
14 import org.simantics.spreadsheet.solver.formula.CellValueVisitor;
15 import org.simantics.spreadsheet.solver.formula.FormulaError2;
16 import org.simantics.spreadsheet.solver.formula.SpreadsheetEvaluationEnvironment;
17 import org.simantics.spreadsheet.solver.formula.parser.ast.AstValue;
19 @SuppressWarnings("rawtypes")
20 public class SpreadsheetCell extends BinarySearch implements SpreadsheetElement, SheetNode {
22 private static final long serialVersionUID = 6616793596542239339L;
24 public static SpreadsheetCell EMPTY;
27 EMPTY = new SpreadsheetCell(null, -1);
29 EMPTY.setStyle(SpreadsheetStyle.empty().getStyleId());
32 private boolean inProgress = false;
33 private int iterations = 0;
35 final private SpreadsheetLine line;
38 final private Map<String, SheetNode> properties;
40 public SpreadsheetCell(SpreadsheetLine line, int column) {
42 this.properties = createProperties();
46 //All SpreadsheetCells have these properties - create them when object is created
47 private Map<String, SheetNode> createProperties() {
48 Map<String, SheetNode> p = new HashMap<>();
49 p.put("typeURI", new SpreadsheetTypeNode(Spreadsheets.CELL_TYPE_URI));
50 p.put("content", new SpreadsheetCellContent(this));
51 p.put("style", new SpreadsheetCellStyle(this));
52 p.put("editable", new SpreadsheetCellEditable(this));
56 public boolean hasExpression() {
57 return content instanceof SpreadsheetFormula || content instanceof SpreadsheetSCLConstant;
60 public void setContent(Object newContent) {
61 this.content = newContent;
64 public int getColumn() {
69 public String getName() {
70 return Spreadsheets.cellName(line.row, column);
74 public Map<?, ?> getChildren() {
75 return Collections.emptyMap();
79 public Map<String, SheetNode> getProperties() {
83 public SpreadsheetBook getBook() {
84 return line.getEngine().getBook();
87 public SpreadsheetEngine getEngine() {
88 return line.getEngine();
91 public <T> T evaluate(SpreadsheetEvaluationEnvironment env) {
92 return evaluate(env, null);
95 @SuppressWarnings("unchecked")
96 public <T> T evaluate(SpreadsheetEvaluationEnvironment env, CellValueVisitor caller) {
98 caller.addReference(makeReferenceKey());
99 if(content instanceof SpreadsheetFormula) {
100 SpreadsheetFormula f = (SpreadsheetFormula)content;
101 if(f.result == null) {
102 CellValueVisitor visitor = new CellValueVisitor(env, this);
103 AstValue value = ((SpreadsheetFormula)content).value;
104 if(this.inProgress == true) this.iterations++;
106 if(!env.getBook().isIterationEnabled()){
107 if(this.inProgress == false){
108 this.inProgress = true;
109 f.result = value.accept(visitor);
111 else f.result = FormulaError2.CIRCULAR_REF.getString();
113 else if(this.iterations<env.iterationLimit){
114 this.inProgress = true;
115 f.result = value.accept(visitor);
121 env.getBook().registerReferences(makeReferenceKey(), visitor.getReferences());
123 this.inProgress = false;
126 } else if (content instanceof SpreadsheetSCLConstant) {
127 SpreadsheetSCLConstant sclConstant = (SpreadsheetSCLConstant) content;
128 Object c = sclConstant.getContent();
129 if(c instanceof Variant) {
130 Variant v = (Variant)c;
132 } else if (c instanceof ExternalRef) {
133 ExternalRefData erd = env.getBook().getExternalRefValue(makeReferenceKey(), (ExternalRef)c);
136 throw new IllegalStateException("Unsupported content " + c);
139 this.inProgress = false;
144 public long makeReferenceKey() {
145 SpreadsheetBook book = getBook();
146 SpreadsheetEngine engine = getEngine();
147 long engineIndex = book.getEngineIndex(engine);
150 return (engineIndex << 40) + (row << 20) + col;
153 public void invalidate() {
154 getEngine().rangeCache = null;
155 if(content instanceof SpreadsheetFormula) {
156 SpreadsheetFormula f = (SpreadsheetFormula)content;
162 public void accept(SpreadsheetVisitor v) {
167 public Optional<SpreadsheetElement> getParent() {
168 return Optional.of(line);
172 public List<SpreadsheetElement> getSpreadsheetChildren() {
173 return Collections.emptyList();
177 public void remove(SpreadsheetElement child) {
178 // TODO Auto-generated method stub
183 public int hashCode() {
184 final int prime = 31;
186 result = prime * result + column;
187 result = prime * result + ((line == null) ? 0 : line.hashCode());
192 public boolean equals(Object obj) {
197 if (getClass() != obj.getClass())
199 SpreadsheetCell other = (SpreadsheetCell) obj;
200 if (column != other.column)
203 if (other.line != null)
205 } else if (!line.equals(other.line))
210 public void setStyle(int styleId) {
211 this.style = styleId;
214 public int getStyle() {
218 public Object getContent() {
222 public Variant getContentVariant(SpreadsheetBook book) {
225 Object content = evaluate(SpreadsheetEvaluationEnvironment.getInstance(book));
226 if(content == null) return Variant.ofInstance("");
227 if(content instanceof Variant) return (Variant)content;
228 if(content instanceof ExternalRefData) return ((ExternalRefData)content).getContent();
229 else return Variant.ofInstance(content);
230 } catch (Throwable t) {
232 return Variant.ofInstance(t.toString());
236 public SpreadsheetLine getLine() {
240 public static SpreadsheetCell empty(SpreadsheetLine line, int column) {
241 SpreadsheetCell cell = new SpreadsheetCell(line, column);
243 cell.setStyle(SpreadsheetStyle.empty().getStyleId());