]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/SpreadsheetCell.java
Spreadsheet changes
[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 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     final private int column;
37     int style;
38     Object content;
39     final private Map<String, SheetNode> properties;
40
41     public SpreadsheetCell(SpreadsheetLine line, int column) {
42         this.properties = createProperties();
43         this.line = line;
44         this.column = column;
45     }
46
47     //All SpreadsheetCells have these properties - create them when object is created
48     private Map<String, SheetNode> createProperties() {
49         Map<String, SheetNode> p = new HashMap<>();         
50         p.put("typeURI", new SpreadsheetTypeNode(Spreadsheets.CELL_TYPE_URI));
51         p.put("content", new SpreadsheetCellContent(this));
52         p.put("style", new SpreadsheetCellStyle(this));
53         p.put("editable", new SpreadsheetCellEditable(this));
54         return p;
55     }
56
57     public boolean hasExpression() {
58         return content instanceof SpreadsheetFormula || content instanceof SpreadsheetSCLConstant; 
59     }
60
61     public void setContent(Object newContent) {
62         this.content = newContent;
63     }
64
65     @Override
66     public String getName() {
67         return Spreadsheets.cellName(line.row, column);
68     }
69
70     @Override
71     public Map<?, ?> getChildren() {
72         return Collections.emptyMap();
73     }
74
75     @Override
76     public Map<String, SheetNode> getProperties() {
77         return properties;
78     }
79
80     public SpreadsheetBook getBook() {
81         return line.getEngine().getBook();
82     }
83
84     public SpreadsheetEngine getEngine() {
85         return line.getEngine();
86     }
87
88     public <T> T evaluate(SpreadsheetEvaluationEnvironment env) {
89         return evaluate(env, null);
90     }
91
92     @SuppressWarnings("unchecked")
93     public <T> T evaluate(SpreadsheetEvaluationEnvironment env, CellValueVisitor caller) {
94         if(caller != null)
95             caller.addReference(makeReferenceKey());
96         if(content instanceof SpreadsheetFormula) {
97             SpreadsheetFormula f = (SpreadsheetFormula)content;
98             if(f.result == null) {
99                 CellValueVisitor visitor = new CellValueVisitor(env, this);
100                 AstValue value = ((SpreadsheetFormula)content).value;
101                 if(this.inProgress == true) this.iterations++;
102
103                 if(!env.getBook().isIterationEnabled()){
104                     if(this.inProgress == false){
105                         this.inProgress = true;
106                         f.result = value.accept(visitor);
107                     }
108                     else f.result = FormulaError2.CIRCULAR_REF.getString();
109                 }
110                 else if(this.iterations<env.iterationLimit){
111                     this.inProgress = true;
112                     f.result = value.accept(visitor);
113                 }
114                 else {
115                     if(f.result==null)
116                         f.result = 0.0;
117                 }
118                 env.getBook().registerReferences(makeReferenceKey(), visitor.getReferences());
119             }
120             this.inProgress = false;
121             this.iterations = 0;
122             return (T)f.result;
123         } else if (content instanceof SpreadsheetSCLConstant) {
124             SpreadsheetSCLConstant sclConstant = (SpreadsheetSCLConstant) content;
125             if(sclConstant.content instanceof Variant) {
126                 Variant v = (Variant)sclConstant.content;
127                 return (T) sclConstant.content;
128             } else if (sclConstant.content instanceof ExternalRef) {
129                 return (T)env.getBook().getExternalRefValue(makeReferenceKey(), (ExternalRef)sclConstant.content);
130             } else {
131                 throw new IllegalStateException();
132             }
133         } else {
134             this.inProgress = false;
135             return (T)content;
136         }
137     }
138
139     public long makeReferenceKey() {
140         SpreadsheetBook book = getBook();
141         SpreadsheetEngine engine = getEngine();
142         long engineIndex = book.getEngineIndex(engine);
143         long row = line.row;
144         long col = column;
145         return (engineIndex << 40) + (row << 20) + col; 
146     }
147
148     public void invalidate() {
149         getEngine().rangeCache = null;
150         if(content instanceof SpreadsheetFormula) {
151             SpreadsheetFormula f = (SpreadsheetFormula)content;
152             f.result = null;
153         }
154     }
155
156     @Override
157     public void accept(SpreadsheetVisitor v) {
158         v.visit(this);
159     }
160
161     @Override
162     public Optional<SpreadsheetElement> getParent() {
163         return Optional.of(line);
164     }
165
166     @Override
167     public List<SpreadsheetElement> getSpreadsheetChildren() {
168         return Collections.emptyList();
169     }
170
171     @Override
172     public void remove(SpreadsheetElement child) {
173         // TODO Auto-generated method stub
174
175     }
176
177     @Override
178     public int hashCode() {
179         final int prime = 31;
180         int result = 1;
181         result = prime * result + column;
182         result = prime * result + ((line == null) ? 0 : line.hashCode());
183         return result;
184     }
185
186     @Override
187     public boolean equals(Object obj) {
188         if (this == obj)
189             return true;
190         if (obj == null)
191             return false;
192         if (getClass() != obj.getClass())
193             return false;
194         SpreadsheetCell other = (SpreadsheetCell) obj;
195         if (column != other.column)
196             return false;
197         if (line == null) {
198             if (other.line != null)
199                 return false;
200         } else if (!line.equals(other.line))
201             return false;
202         return true;
203     }
204
205     public void setStyle(int styleId) {
206         this.style = styleId;
207     }
208
209     public int getStyle() {
210         return style;
211     }
212
213     public Object getContent() {
214         return content;
215     }
216
217     public static SpreadsheetCell empty(SpreadsheetLine line, int column) {
218         SpreadsheetCell cell =  new SpreadsheetCell(line, column);
219         cell.setContent("");
220         cell.setStyle(SpreadsheetStyle.empty().getStyleId());
221         return cell;
222     }
223
224 }