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 extends BinarySearch 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; int style; Object content; final private Map properties; public SpreadsheetCell(SpreadsheetLine line, int column) { super(column); this.properties = createProperties(); this.line = line; } //All SpreadsheetCells have these properties - create them when object is created private Map createProperties() { Map 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 getProperties() { return properties; } public SpreadsheetBook getBook() { return line.getEngine().getBook(); } public SpreadsheetEngine getEngine() { return line.getEngine(); } public T evaluate(SpreadsheetEvaluationEnvironment env) { return evaluate(env, null); } @SuppressWarnings("unchecked") public 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 getParent() { return Optional.of(line); } @Override public List 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 Variant getContentVariant(SpreadsheetBook book) { try { Object content = evaluate(SpreadsheetEvaluationEnvironment.getInstance(book)); if(content == null) return Variant.ofInstance(""); if(content instanceof Variant) return (Variant)content; if(content instanceof ExternalRefData) return ((ExternalRefData)content).getContent(); else return Variant.ofInstance(content); } catch (Throwable t) { t.printStackTrace(); return Variant.ofInstance(t.toString()); } } public SpreadsheetLine getLine() { return line; } public static SpreadsheetCell empty(SpreadsheetLine line, int column) { SpreadsheetCell cell = new SpreadsheetCell(line, column); cell.setContent(""); cell.setStyle(SpreadsheetStyle.empty().getStyleId()); return cell; } }