]> 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     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             if(sclConstant.content instanceof Variant) {
130                 Variant v = (Variant)sclConstant.content;
131                 return (T) sclConstant.content;
132             } else if (sclConstant.content instanceof ExternalRef) {
133                 return (T)env.getBook().getExternalRefValue(makeReferenceKey(), (ExternalRef)sclConstant.content);
134             } else {
135                 throw new IllegalStateException();
136             }
137         } else {
138             this.inProgress = false;
139             return (T)content;
140         }
141     }
142
143     public long makeReferenceKey() {
144         SpreadsheetBook book = getBook();
145         SpreadsheetEngine engine = getEngine();
146         long engineIndex = book.getEngineIndex(engine);
147         long row = line.row;
148         long col = column;
149         return (engineIndex << 40) + (row << 20) + col; 
150     }
151
152     public void invalidate() {
153         getEngine().rangeCache = null;
154         if(content instanceof SpreadsheetFormula) {
155             SpreadsheetFormula f = (SpreadsheetFormula)content;
156             f.result = null;
157         }
158     }
159
160     @Override
161     public void accept(SpreadsheetVisitor v) {
162         v.visit(this);
163     }
164
165     @Override
166     public Optional<SpreadsheetElement> getParent() {
167         return Optional.of(line);
168     }
169
170     @Override
171     public List<SpreadsheetElement> getSpreadsheetChildren() {
172         return Collections.emptyList();
173     }
174
175     @Override
176     public void remove(SpreadsheetElement child) {
177         // TODO Auto-generated method stub
178
179     }
180
181     @Override
182     public int hashCode() {
183         final int prime = 31;
184         int result = 1;
185         result = prime * result + column;
186         result = prime * result + ((line == null) ? 0 : line.hashCode());
187         return result;
188     }
189
190     @Override
191     public boolean equals(Object obj) {
192         if (this == obj)
193             return true;
194         if (obj == null)
195             return false;
196         if (getClass() != obj.getClass())
197             return false;
198         SpreadsheetCell other = (SpreadsheetCell) obj;
199         if (column != other.column)
200             return false;
201         if (line == null) {
202             if (other.line != null)
203                 return false;
204         } else if (!line.equals(other.line))
205             return false;
206         return true;
207     }
208
209     public void setStyle(int styleId) {
210         this.style = styleId;
211     }
212
213     public int getStyle() {
214         return style;
215     }
216
217     public Object getContent() {
218         return content;
219     }
220
221     public static SpreadsheetCell empty(SpreadsheetLine line, int column) {
222         SpreadsheetCell cell =  new SpreadsheetCell(line, column);
223         cell.setContent("");
224         cell.setStyle(SpreadsheetStyle.empty().getStyleId());
225         return cell;
226     }
227
228 }