]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - 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
diff --git a/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/SpreadsheetCell.java b/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/SpreadsheetCell.java
new file mode 100644 (file)
index 0000000..5b732cf
--- /dev/null
@@ -0,0 +1,230 @@
+package org.simantics.spreadsheet.solver;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.simantics.databoard.binding.mutable.Variant;
+import org.simantics.spreadsheet.ExternalRef;
+import org.simantics.spreadsheet.SpreadsheetCellStyle;
+import org.simantics.spreadsheet.SpreadsheetVisitor;
+import org.simantics.spreadsheet.Spreadsheets;
+import org.simantics.spreadsheet.solver.formula.CellValueVisitor;
+import org.simantics.spreadsheet.solver.formula.FormulaError2;
+import org.simantics.spreadsheet.solver.formula.SpreadsheetEvaluationEnvironment;
+import org.simantics.spreadsheet.solver.formula.parser.ast.AstValue;
+
+@SuppressWarnings("rawtypes")
+public class SpreadsheetCell implements SpreadsheetElement, SheetNode {
+
+    private static final long serialVersionUID = 6616793596542239339L;
+
+    public static SpreadsheetCell EMPTY;
+
+    static {
+        EMPTY = new SpreadsheetCell(null, -1);
+        EMPTY.setContent("");
+        EMPTY.setStyle(SpreadsheetStyle.empty().getStyleId());
+    }
+
+    private boolean inProgress = false;
+    private int iterations = 0;
+
+    final private SpreadsheetLine line;
+    final private int column;
+    int style;
+    private Object content;
+    final private Map<String, SheetNode> properties;
+
+    public SpreadsheetCell(SpreadsheetLine line, int column) {
+        this.properties = createProperties();
+        this.line = line;
+        this.column = column;
+    }
+
+    //All SpreadsheetCells have these properties - create them when object is created
+    private Map<String, SheetNode> createProperties() {
+        Map<String, SheetNode> p = new HashMap<>();        
+        p.put("typeURI", new SpreadsheetTypeNode(Spreadsheets.CELL_TYPE_URI));
+        p.put("content", new SpreadsheetCellContent(this));
+        p.put("style", new SpreadsheetCellStyle(this));
+        p.put("editable", new SpreadsheetCellEditable(this));
+        return p;
+    }
+
+    public boolean hasExpression() {
+        return content instanceof SpreadsheetFormula || content instanceof SpreadsheetSCLConstant; 
+    }
+
+    public void setContent(Object newContent) {
+        this.content = newContent;
+    }
+    
+    public int getColumn() {
+       return column;
+    }
+
+    @Override
+    public String getName() {
+        return Spreadsheets.cellName(line.row, column);
+    }
+
+    @Override
+    public Map<?, ?> getChildren() {
+        return Collections.emptyMap();
+    }
+
+    @Override
+    public Map<String, SheetNode> getProperties() {
+        return properties;
+    }
+
+    public SpreadsheetBook getBook() {
+        return line.getEngine().getBook();
+    }
+
+    public SpreadsheetEngine getEngine() {
+        return line.getEngine();
+    }
+
+    public <T> T evaluate(SpreadsheetEvaluationEnvironment env) {
+        return evaluate(env, null);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T evaluate(SpreadsheetEvaluationEnvironment env, CellValueVisitor caller) {
+        if(caller != null)
+            caller.addReference(makeReferenceKey());
+        if(content instanceof SpreadsheetFormula) {
+            SpreadsheetFormula f = (SpreadsheetFormula)content;
+            if(f.result == null) {
+                CellValueVisitor visitor = new CellValueVisitor(env, this);
+                AstValue value = ((SpreadsheetFormula)content).value;
+                if(this.inProgress == true) this.iterations++;
+
+                if(!env.getBook().isIterationEnabled()){
+                    if(this.inProgress == false){
+                        this.inProgress = true;
+                        f.result = value.accept(visitor);
+                    }
+                    else f.result = FormulaError2.CIRCULAR_REF.getString();
+                }
+                else if(this.iterations<env.iterationLimit){
+                    this.inProgress = true;
+                    f.result = value.accept(visitor);
+                }
+                else {
+                    if(f.result==null)
+                        f.result = 0.0;
+                }
+                env.getBook().registerReferences(makeReferenceKey(), visitor.getReferences());
+            }
+            this.inProgress = false;
+            this.iterations = 0;
+            return (T)f.result;
+        } else if (content instanceof SpreadsheetSCLConstant) {
+            SpreadsheetSCLConstant sclConstant = (SpreadsheetSCLConstant) content;
+            Object c = sclConstant.getContent();
+            if(c instanceof Variant) {
+                Variant v = (Variant)c;
+                return (T) c;
+            } else if (c instanceof ExternalRef) {
+                ExternalRefData erd = env.getBook().getExternalRefValue(makeReferenceKey(), (ExternalRef)c); 
+                return (T)erd;
+            } else {
+                throw new IllegalStateException("Unsupported content " + c);
+            }
+        } else {
+            this.inProgress = false;
+            return (T)content;
+        }
+    }
+
+    public long makeReferenceKey() {
+        SpreadsheetBook book = getBook();
+        SpreadsheetEngine engine = getEngine();
+        long engineIndex = book.getEngineIndex(engine);
+        long row = line.row;
+        long col = column;
+        return (engineIndex << 40) + (row << 20) + col; 
+    }
+
+    public void invalidate() {
+        getEngine().rangeCache = null;
+        if(content instanceof SpreadsheetFormula) {
+            SpreadsheetFormula f = (SpreadsheetFormula)content;
+            f.result = null;
+        }
+    }
+
+    @Override
+    public void accept(SpreadsheetVisitor v) {
+        v.visit(this);
+    }
+
+    @Override
+    public Optional<SpreadsheetElement> getParent() {
+        return Optional.of(line);
+    }
+
+    @Override
+    public List<SpreadsheetElement> getSpreadsheetChildren() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void remove(SpreadsheetElement child) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + column;
+        result = prime * result + ((line == null) ? 0 : line.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        SpreadsheetCell other = (SpreadsheetCell) obj;
+        if (column != other.column)
+            return false;
+        if (line == null) {
+            if (other.line != null)
+                return false;
+        } else if (!line.equals(other.line))
+            return false;
+        return true;
+    }
+
+    public void setStyle(int styleId) {
+        this.style = styleId;
+    }
+
+    public int getStyle() {
+        return style;
+    }
+
+    public Object getContent() {
+        return content;
+    }
+
+    public static SpreadsheetCell empty(SpreadsheetLine line, int column) {
+        SpreadsheetCell cell =  new SpreadsheetCell(line, column);
+        cell.setContent("");
+        cell.setStyle(SpreadsheetStyle.empty().getStyleId());
+        return cell;
+    }
+
+}