]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/SpreadsheetCell.java
SCL API for direct access to SpreadsheetBooks
[simantics/platform.git] / bundles / org.simantics.spreadsheet / src / org / simantics / spreadsheet / solver / SpreadsheetCell.java
1 package org.simantics.spreadsheet.solver;
2
3 import java.util.Collections;
4 import java.util.HashMap;
5 import java.util.List;
6 import java.util.Map;
7 import java.util.Optional;
8
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;
18
19 @SuppressWarnings("rawtypes")
20 public class SpreadsheetCell extends BinarySearch implements SpreadsheetElement, SheetNode {
21
22     private static final long serialVersionUID = 6616793596542239339L;
23
24     public static SpreadsheetCell EMPTY;
25
26     static {
27         EMPTY = new SpreadsheetCell(null, -1);
28         EMPTY.setContent("");
29         EMPTY.setStyle(SpreadsheetStyle.empty().getStyleId());
30     }
31
32     private boolean inProgress = false;
33     private int iterations = 0;
34
35     final private SpreadsheetLine line;
36     int style;
37     Object content;
38     final private Map<String, SheetNode> properties;
39
40     public SpreadsheetCell(SpreadsheetLine line, int column) {
41         super(column);
42         this.properties = createProperties();
43         this.line = line;
44     }
45
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));
53         return p;
54     }
55
56     public boolean hasExpression() {
57         return content instanceof SpreadsheetFormula || content instanceof SpreadsheetSCLConstant; 
58     }
59
60     public void setContent(Object newContent) {
61         this.content = newContent;
62     }
63     
64     public int getColumn() {
65        return column;
66     }
67
68     @Override
69     public String getName() {
70         return Spreadsheets.cellName(line.row, column);
71     }
72
73     @Override
74     public Map<?, ?> getChildren() {
75         return Collections.emptyMap();
76     }
77
78     @Override
79     public Map<String, SheetNode> getProperties() {
80         return properties;
81     }
82
83     public SpreadsheetBook getBook() {
84         return line.getEngine().getBook();
85     }
86
87     public SpreadsheetEngine getEngine() {
88         return line.getEngine();
89     }
90
91     public <T> T evaluate(SpreadsheetEvaluationEnvironment env) {
92         return evaluate(env, null);
93     }
94
95     @SuppressWarnings("unchecked")
96     public <T> T evaluate(SpreadsheetEvaluationEnvironment env, CellValueVisitor caller) {
97         if(caller != null)
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++;
105
106                 if(!env.getBook().isIterationEnabled()){
107                     if(this.inProgress == false){
108                         this.inProgress = true;
109                         f.result = value.accept(visitor);
110                     }
111                     else f.result = FormulaError2.CIRCULAR_REF.getString();
112                 }
113                 else if(this.iterations<env.iterationLimit){
114                     this.inProgress = true;
115                     f.result = value.accept(visitor);
116                 }
117                 else {
118                     if(f.result==null)
119                         f.result = 0.0;
120                 }
121                 env.getBook().registerReferences(makeReferenceKey(), visitor.getReferences());
122             }
123             this.inProgress = false;
124             this.iterations = 0;
125             return (T)f.result;
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;
131                 return (T) c;
132             } else if (c instanceof ExternalRef) {
133                 ExternalRefData erd = env.getBook().getExternalRefValue(makeReferenceKey(), (ExternalRef)c); 
134                 return (T)erd;
135             } else {
136                 throw new IllegalStateException("Unsupported content " + c);
137             }
138         } else {
139             this.inProgress = false;
140             return (T)content;
141         }
142     }
143
144     public long makeReferenceKey() {
145         SpreadsheetBook book = getBook();
146         SpreadsheetEngine engine = getEngine();
147         long engineIndex = book.getEngineIndex(engine);
148         long row = line.row;
149         long col = column;
150         return (engineIndex << 40) + (row << 20) + col; 
151     }
152
153     public void invalidate() {
154         getEngine().rangeCache = null;
155         if(content instanceof SpreadsheetFormula) {
156             SpreadsheetFormula f = (SpreadsheetFormula)content;
157             f.result = null;
158         }
159     }
160
161     @Override
162     public void accept(SpreadsheetVisitor v) {
163         v.visit(this);
164     }
165
166     @Override
167     public Optional<SpreadsheetElement> getParent() {
168         return Optional.of(line);
169     }
170
171     @Override
172     public List<SpreadsheetElement> getSpreadsheetChildren() {
173         return Collections.emptyList();
174     }
175
176     @Override
177     public void remove(SpreadsheetElement child) {
178         // TODO Auto-generated method stub
179
180     }
181
182     @Override
183     public int hashCode() {
184         final int prime = 31;
185         int result = 1;
186         result = prime * result + column;
187         result = prime * result + ((line == null) ? 0 : line.hashCode());
188         return result;
189     }
190
191     @Override
192     public boolean equals(Object obj) {
193         if (this == obj)
194             return true;
195         if (obj == null)
196             return false;
197         if (getClass() != obj.getClass())
198             return false;
199         SpreadsheetCell other = (SpreadsheetCell) obj;
200         if (column != other.column)
201             return false;
202         if (line == null) {
203             if (other.line != null)
204                 return false;
205         } else if (!line.equals(other.line))
206             return false;
207         return true;
208     }
209
210     public void setStyle(int styleId) {
211         this.style = styleId;
212     }
213
214     public int getStyle() {
215         return style;
216     }
217
218     public Object getContent() {
219         return content;
220     }
221     
222     public Variant getContentVariant(SpreadsheetBook book) {
223         
224         try {
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) {
231             t.printStackTrace();
232             return Variant.ofInstance(t.toString());
233         }
234     }
235     
236     public SpreadsheetLine getLine() {
237         return line;
238     }
239
240     public static SpreadsheetCell empty(SpreadsheetLine line, int column) {
241         SpreadsheetCell cell =  new SpreadsheetCell(line, column);
242         cell.setContent("");
243         cell.setStyle(SpreadsheetStyle.empty().getStyleId());
244         return cell;
245     }
246
247 }