package org.simantics.spreadsheet.graph; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.mutable.Variant; import org.simantics.layer0.Layer0; import org.simantics.simulator.toolkit.db.StandardVariableNodeManager; import org.simantics.simulator.variable.exceptions.NodeManagerException; import org.simantics.spreadsheet.SpreadsheetCellStyle; import org.simantics.spreadsheet.resource.SpreadsheetResource; import org.simantics.spreadsheet.solver.SheetNode; import org.simantics.spreadsheet.solver.SpreadsheetBook; import org.simantics.spreadsheet.solver.SpreadsheetBook.SpreadsheetBookListener; import org.simantics.spreadsheet.solver.SpreadsheetCell; import org.simantics.spreadsheet.solver.SpreadsheetCellContent; import org.simantics.spreadsheet.solver.SpreadsheetCellContentExpression; import org.simantics.spreadsheet.solver.SpreadsheetCellEditable; import org.simantics.spreadsheet.solver.SpreadsheetFormula; import org.simantics.spreadsheet.solver.SpreadsheetSCLConstant; import org.simantics.spreadsheet.solver.SpreadsheetTypeNode; import org.simantics.structural.stubs.StructuralResource2; @SuppressWarnings("rawtypes") public class SpreadsheetNodeManager extends StandardVariableNodeManager { public SpreadsheetNodeManager(SpreadsheetRealm realm) { super(realm, realm.getEngine()); realm.getEngine().registerListener(new SpreadsheetBookListener() { @Override public void cellsChanged(Collection cells) { realm.asyncExec(new Runnable() { @Override public void run() { for(SpreadsheetCell cell : cells) { refreshVariable(new SpreadsheetCellContent(cell)); Object content = cell.getContent(); if(content instanceof SpreadsheetFormula || content instanceof SpreadsheetSCLConstant) refreshVariable(new SpreadsheetCellContentExpression(cell)); } } }); } }); } static final Set COMPONENT_CLASS = Collections.singleton(StructuralResource2.URIs.Component); @Override public Set getClassifications(SheetNode node) throws NodeManagerException { checkThreadAccess(); if(isRoot(node)) return COMPONENT_CLASS; else return Collections.emptySet(); } @Override public String getPropertyURI(SheetNode parent, SheetNode property) { if(property instanceof SpreadsheetCellContent) { return SpreadsheetResource.URIs.Cell_content; } else if(property instanceof SpreadsheetTypeNode) { return Layer0.URIs.typeURI; } else if(property instanceof SpreadsheetCellContentExpression) { return Layer0.URIs.SCLValue_expression; } else if (property instanceof SpreadsheetCellStyle) { return SpreadsheetResource.URIs.Cell_style; } else if (property instanceof SpreadsheetCellEditable){ return SpreadsheetResource.URIs.Cell_editable; } else { return null; } } //Custom setValue logic for SpreadsheetNodeManager - calls the setValueAndFireSelectedListeners @Override public void setValue(SheetNode node, Object value, Binding binding) throws NodeManagerException { Set dirtyNodeContents = findDirtyNodeContents(node); super.setValueAndFireSelectedListeners(node, value, binding, dirtyNodeContents); if(value instanceof SpreadsheetFormula) { SpreadsheetCellContent scc = (SpreadsheetCellContent)node; SpreadsheetCellContentExpression scce = new SpreadsheetCellContentExpression(scc.cell); // We need to also refresh the expression variable in this case refreshVariable(scce); } } //Find the cells that are used by this cell and their SpreadsheetContents, so that they can be marked as dirty later public Set findDirtyNodeContents(SheetNode node){ Set dirty = new HashSet<>(); SpreadsheetCell sscell = null; if(node instanceof SpreadsheetCell) { sscell = (SpreadsheetCell)node; } else if (node instanceof SpreadsheetCellContent) { sscell = ((SpreadsheetCellContent)node).cell; } if(sscell != null) { Set result = ((SpreadsheetRealm)super.getRealm()).getEngine().invalidate(sscell); dirty.addAll(result); } Set dirtyNodeContents = new HashSet<>(); for(SheetNode cell : dirty) { Map properties = cell.getProperties(); dirtyNodeContents.add((SpreadsheetCellContent)properties.get("content")); } return dirtyNodeContents; } @Override protected Variant getEngineVariantOrCached(SheetNode node) throws NodeManagerException { Variant variant = valueCache.get(node); if(variant == null) { Object value = realm.getEngine().getEngineValue(node); Binding binding = realm.getEngine().getEngineBinding(node); variant = new Variant(binding, value); valueCache.put(node, variant); } return variant; } }