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