Spreadsheet updates cell values properly 49/1949/1
authorMiro Richard Eklund <miro.eklund@semantum.fi>
Wed, 25 Jul 2018 09:33:33 +0000 (12:33 +0300)
committerMiro Richard Eklund <miro.eklund@semantum.fi>
Wed, 25 Jul 2018 09:33:33 +0000 (12:33 +0300)
Cells referencing other cells weren't updated after change
"8c8283a01e63980527d605936286747006bea601" (see in History view), in
StandardNodeManager.java. I added a new setValue function that takes a
list of Nodes that need to be updated (removes them from valueCache),
which allows only specific cells to be updated when another cell is
updated.
I also removed invalidation code from Spreadsheet's "All.java" class and
added them to the value updated in SpreadsheetNodeManager, which
invalidates recursively the cells the use another cell.
I also made sure that SpreadsheetCells jave the same properties through
their life-cycle, rather than creating a properties map whenever the
properties are called.

gitlab #48
gitlab #54
gitlab #55

Change-Id: I125f644e014310937ed7697e9f44ec33825f9b0f

bundles/org.simantics.simulator.toolkit/src/org/simantics/simulator/toolkit/StandardNodeManager.java
bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/SpreadsheetBook.java
bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/SpreadsheetCell.java
bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/SpreadsheetNodeManager.java
bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/function/All.java
bundles/org.simantics.spreadsheet.ui/src/org/simantics/spreadsheet/ui/SelectionListener.java
bundles/org.simantics.spreadsheet.ui/src/org/simantics/spreadsheet/ui/SpreadsheetModel.java
bundles/org.simantics.spreadsheet.ui/src/org/simantics/spreadsheet/ui/TextTableCellEditor.java

index 8f1d1cf53c9c2a0c29ce8a6fbefd499128646df7..8a51fd330764959e7c62f4cc292c2ab2e36fb0c0 100644 (file)
@@ -322,6 +322,23 @@ public abstract class StandardNodeManager<Node, Engine extends StandardNodeManag
     @Override
     public void setValue(Node node, Object value, Binding binding)
             throws NodeManagerException {
+       updateValueInner(node, value, binding);
+        refreshVariable(node);
+    }
+
+    //Update the value of the node and remove from valueCache only the references nodes
+    public void setValueAndFireSelectedListeners(Node node, Object value, Binding binding, Set<Node> references) throws NodeManagerException {
+       if(references.size() > 0) {
+               for(Node n : references) {
+                       valueCache.remove(n);
+               }
+       }
+       updateValueInner(node, value, binding);
+       fireNodeListenersSync();
+    }
+    
+    //Update the value of the node helper method
+    private void updateValueInner(Node node, Object value, Binding binding) throws NodeManagerException {
         checkThreadAccess();
         Binding targetBinding = realm.getEngine().getEngineBinding(node);
         if(binding.equals(targetBinding)) {
@@ -341,7 +358,6 @@ public abstract class StandardNodeManager<Node, Engine extends StandardNodeManag
                 throw new NodeManagerException(e);
             }
         }
-        refreshVariable(node);
     }
 
     @Override
index f87ce4d0675e851fee84a432d093241f38245607..d64d008edf713b1cfaf33a3e0fe28261bf188447 100644 (file)
@@ -6,9 +6,11 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.Set;
 
 import org.simantics.databoard.Bindings;
 import org.simantics.databoard.binding.Binding;
@@ -365,7 +367,26 @@ public class SpreadsheetBook implements StandardNodeManagerSupport<SheetNode>, S
                v.visit(this);
        }
        
-       public List<SpreadsheetCell> invalidate(SpreadsheetCell cell) {
+       //Recursively find all SpreadsheetCells, invalidate them and return them all as a set
+       public Set<SpreadsheetCell> invalidate(SpreadsheetCell cell) {
+               Set<SpreadsheetCell> result = new HashSet<>();
+               result.add(cell);
+               cell.invalidate();
+               long refKey = cell.makeReferenceKey();
+               AbstractLongSet refs = referenceMap.remove(refKey);
+               if(refs == null) return result;
+               for(long ref : refs) {
+                       long sheet = ref >> 40;
+                       long row = (ref >> 20) & 0xFFFFF;
+                       long col = (ref) & 0xFFFFF;
+                       SpreadsheetCell referer = get(sheets.get((int)sheet), (int)row, (int)col);
+                       result.addAll(invalidate(referer));
+               }
+               return result;
+       }
+       
+       @Deprecated
+       public List<SpreadsheetCell> invalidateShallow(SpreadsheetCell cell) {
                ArrayList<SpreadsheetCell> result = new ArrayList<>();
                result.add(cell);
                cell.invalidate();
index b4e83ede1ba0bf9ccff9e92bc7b438e99178436a..0ee66cf075142e57f94f27405cfb1609e17c8785 100644 (file)
@@ -31,12 +31,24 @@ public class SpreadsheetCell implements SpreadsheetElement, SheetNode {
        final private int column;
        int style;
        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(SpreadsheetResource.URIs.Cell));
+           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; 
        }
@@ -66,16 +78,9 @@ public class SpreadsheetCell implements SpreadsheetElement, SheetNode {
        
        @Override
        public Map<String, SheetNode> getProperties() {
-           Map<String, SheetNode> properties = new HashMap<>();
-           
            if (GraphUI.DEBUG)
                System.out.println("SpreadsheetCell.getProperties: " + this + " " + content + " " + style);
-           
-           properties.put("typeURI", new SpreadsheetTypeNode(SpreadsheetResource.URIs.Cell));
-           properties.put("content", new SpreadsheetCellContent(this));
-        properties.put("style", new SpreadsheetCellStyle(this));
-        properties.put("editable", new SpreadsheetCellEditable(this));
-           return properties;
+           return properties; //Return this SpreadsheetCells's properties, rather than a new HashMap
        }
        
        public SpreadsheetBook getBook() {
index 56985d16c948c6754551484294381184e2eb1b62..caa6dc23f4602d10589187018c99f66a9f1f9a24 100644 (file)
@@ -1,8 +1,11 @@
 package org.simantics.spreadsheet.graph;
 
 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.layer0.Layer0;
 import org.simantics.simulator.toolkit.StandardNodeManager;
 import org.simantics.simulator.variable.exceptions.NodeManagerException;
@@ -43,5 +46,36 @@ public class SpreadsheetNodeManager extends StandardNodeManager<SheetNode, Sprea
             return null;
         }
     }
-
+    
+    //Custom setValue logic for SpreadsheetNodeManager - calls the setValueAndFireSelectedListeners
+    @Override
+    public void setValue(SheetNode node, Object value, Binding binding) throws NodeManagerException {
+       Set<SheetNode> dirtyNodeContents = findDirtyNodeContents(node);
+       super.setValueAndFireSelectedListeners(node, value, binding, dirtyNodeContents);
+    }
+    
+    //Find the cells that are used by this cell and their SpreadsheetContents, so that they can be marked as dirty later
+    public Set<SheetNode> findDirtyNodeContents(SheetNode node){
+       Set<SheetNode> 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<SpreadsheetCell> result = ((SpreadsheetRealm)super.getRealm()).getEngine().invalidate(sscell);
+               dirty.addAll(result);
+       }
+                       
+       Set<SheetNode> dirtyNodeContents = new HashSet<>();
+       for(SheetNode cell : dirty) {
+               Map<String, SheetNode> properties = cell.getProperties();
+               dirtyNodeContents.add((SpreadsheetCellContent)properties.get("content"));
+       }
+       
+       return dirtyNodeContents;
+    }
 }
index 39e5778f9ddd5bfef7acee410973dc9f008f61df..98ef90231fc6be36999667b377ad46fe1cd5b516 100644 (file)
@@ -200,7 +200,7 @@ public class All {
             SpreadsheetCell sc = book.get(sheet.getName(graph), r.startRow, r.startColumn);
             sc.setContent(value);
 //          book.accept(new InvalidateAll());
-            List<SpreadsheetCell> changed = book.invalidate(sc);
+//                     List<SpreadsheetCell> changed = book.invalidate(sc); //Invalidation handled by SpreadsheetNodeManager
             realm.asyncExec(new Runnable() {
 
                 @Override
index d2eece5bd2b6275927f5980c0d30841d5c7c5219..8a8da732b3e121c082dd8ac3aab4cd22d65ba31c 100644 (file)
@@ -62,7 +62,16 @@ public class SelectionListener implements ListSelectionListener {
 
                        final Object cell = table.getValueAt(selectedRows[0], selectedColumns[0]);
                        if(cell != null) {
-                               String expression = clientModel.getPossiblePropertyAt(SpreadsheetUtils.cellName(selectedRows[0], selectedColumns[0]), ClientModel.CONTENT_EXPRESSION);
+
+                               String expression = "";
+
+                               Object expressionO = clientModel.getPossiblePropertyAt(SpreadsheetUtils.cellName(selectedRows[0], selectedColumns[0]), ClientModel.CONTENT_EXPRESSION);
+                               if(expressionO instanceof String) {
+                                       expression = (String)expressionO;
+                               } else if(expressionO instanceof Variant) {
+                                       expression = ((Variant)expressionO).toString();
+                               }
+
                                if(expression == null) {
                                        Variant content = SpreadsheetUtils.getSafeClientVariant(clientModel, SpreadsheetUtils.cellName(selectedRows[0], selectedColumns[0]), ClientModel.CONTENT);
                                        if(content != null)
index 93f455702591f7ac1d981cf5b91f944377cfc565..5339796bddbf62aaa945f1f64dba4f6c7a91ce16 100644 (file)
@@ -2,6 +2,7 @@ package org.simantics.spreadsheet.ui;
 
 import java.awt.BorderLayout;
 import java.awt.Color;
+import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.Font;
 import java.awt.Frame;
@@ -691,6 +692,9 @@ public class SpreadsheetModel {
                        etl = new ExpressionTextListener(expression, serverInterface.getAdapter(CellEditor.class));
                        expression.addFocusListener(etl);
                        expression.addKeyListener(etl);
+
+                       //Large default size so that the expression field is clearly visible
+                       expression.setPreferredSize(new Dimension(600, 32));
                        
                     sheets.addItemListener(sheetsListener);
 
index 2c84b6ad1d16abc8662e052c67f4bd9f2c394ed6..24fade56ae6a839b93195f7e723a699c42475256 100644 (file)
@@ -136,7 +136,14 @@ class TextTableCellEditor extends DefaultCellEditor implements SpreadsheetCellEd
        String str = (String)getCellEditorValue();
 
        String cellName = SpreadsheetUtils.cellName(row, column);
-       String expression = clientModel.getPossiblePropertyAt(cellName, ClientModel.CONTENT_EXPRESSION);
+       Object expressionO = clientModel.getPossiblePropertyAt(cellName, ClientModel.CONTENT_EXPRESSION);
+       String expression = null;
+       if(expressionO instanceof String) {
+               expression = (String)expressionO;
+       } else if(expressionO instanceof Variant) {
+               expression = ((Variant)expressionO).getValue().toString();
+       }
+       
                if(expression == null) {
                        Variant content = SpreadsheetUtils.getSafeClientVariant(clientModel, cellName, ClientModel.CONTENT);
                        if(content != null)