Preliminary implementation to update only changed profile entries
authorJussi Koskela <jussi.koskela@semantum.fi>
Wed, 24 Oct 2018 12:23:23 +0000 (15:23 +0300)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Wed, 14 Nov 2018 12:10:34 +0000 (14:10 +0200)
Marks related elements dirty.

Change-Id: Id93d9126393f6840cb028c11cac095b1078f229e
(cherry picked from commit ecfd4cc9881712d59ddfc2023db382ad4f3a9be9)

bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/ConstantStyle.java
bundles/org.simantics.diagram/src/org/simantics/diagram/elements/TextGridNode.java
bundles/org.simantics.diagram/src/org/simantics/diagram/profile/ShowRelatedElements.java
bundles/org.simantics.diagram/src/org/simantics/diagram/profile/StyleBase.java
bundles/org.simantics.diagram/src/org/simantics/diagram/profile/TextGridStyle.java
bundles/org.simantics.scenegraph.profile/src/org/simantics/scenegraph/profile/Observer.java
bundles/org.simantics.scenegraph.profile/src/org/simantics/scenegraph/profile/Style.java
bundles/org.simantics.scenegraph.profile/src/org/simantics/scenegraph/profile/common/ProfileObserver.java

index 4a59f4b3c8e96268a2097746cfc7accbeb452e56..e81d483bb93a3a6efe89b8786c93e6a60356e030 100644 (file)
@@ -38,6 +38,7 @@ public class ConstantStyle implements Style {
     final String name;
     final Map<String, Object> values = new HashMap<String, Object>();
     ObserverGroupListener listener = null;
+    double priority;
 
     public ConstantStyle(ReadGraph graph, Resource style) throws DatabaseException {
         Layer0 L0 = Layer0.getInstance(graph);
@@ -51,6 +52,14 @@ public class ConstantStyle implements Style {
         }
     }
 
+    public void setPriority(double priority) {
+        this.priority = priority;
+    }
+    
+    public double getPriority() {
+        return priority;
+    }
+    
     private Object haxx(String key, Object value) {
         if("alpha".equals(key)) {
             return AlphaComposite.getInstance(AlphaComposite. SRC_OVER, Float.parseFloat((String)value));
@@ -128,6 +137,16 @@ public class ConstantStyle implements Style {
         }
 
     }
+    
+    @Override
+    public final void apply2(Object item, final EvaluationContext evaluationContext) {
+        final DataNodeMap map = evaluationContext.getConstant(ProfileKeys.NODE_MAP);
+        final INode node = map.getNode(item);
+        
+        for(Map.Entry<String, Object> value : values.entrySet()) {
+            ProfileVariables.claimNodeProperty(node, value.getKey(), value.getValue(), evaluationContext);
+        }
+    }
 
     @Override
     public String toString() {
index 227dea5b1771b841accceae981e52878a3c6e8f2..be0f23a590f62bb2a5009641a77d30b2847cd6ae 100644 (file)
@@ -138,7 +138,7 @@ public class TextGridNode extends G2DParentNode implements Decoration {
         }
     }
 
-    private int computeRows() {
+    public int computeRows() {
         MaxY maxy = new MaxY();
         nodes.forEachKey(maxy);
         return maxy.max;
@@ -245,6 +245,7 @@ public class TextGridNode extends G2DParentNode implements Decoration {
     }
 
     public void removeRow(int y) {
+        rowIds.remove(y);
         List<Cell> row = peekRowCells(y);
         if (row.isEmpty())
             return;
index a18191a671e9497151ad3c105e6f10da37821912..cd4786088afc2ad4358e5b51eb17be19aca7d609 100644 (file)
@@ -178,7 +178,7 @@ public class ShowRelatedElements extends StyleBase<Object> {
     public void applyStyleForItem(EvaluationContext evaluationContext, DataNodeMap map, Object item, Object value) {
         INode node = map.getNode(item);
         if (node == null) {
-            evaluationContext.update();
+            evaluationContext.update(this, item);
             return;
         }
 
index 9978076c641abd89d207c86610f664c609fc1b0b..fee1e8546d7e96e07bf13a21f53b98f26afac6c4 100644 (file)
@@ -27,8 +27,10 @@ import org.simantics.db.layer0.variable.Variable;
 import org.simantics.db.procedure.Listener;
 import org.simantics.db.request.Read;
 import org.simantics.diagram.stubs.DiagramResource;
+import org.simantics.g2d.canvas.Hints;
 import org.simantics.g2d.canvas.ICanvasContext;
 import org.simantics.g2d.diagram.IDiagram;
+import org.simantics.g2d.diagram.handler.DataElementMap;
 import org.simantics.g2d.element.IElement;
 import org.simantics.scenegraph.INode;
 import org.simantics.scenegraph.profile.DataNodeMap;
@@ -67,6 +69,7 @@ import org.simantics.utils.datastructures.Pair;
 public abstract class StyleBase<Result> implements Style {
 
     private Object identity;
+    private double priority;
 
     public StyleBase(Object identity) {
         this.identity = identity;
@@ -81,6 +84,14 @@ public abstract class StyleBase<Result> implements Style {
         return (T)identity;
     }
 
+    public void setPriority(double priority) {
+        this.priority = priority;
+    }
+    
+    public double getPriority() {
+        return priority;
+    }
+    
     @Override
     public int hashCode() {
         final int prime = 31;
@@ -207,7 +218,7 @@ public abstract class StyleBase<Result> implements Style {
             StyleBaseData.getInstance().removeValue(new Tuple3(this, runtimeDiagram, object));
         else
             StyleBaseData.getInstance().putValue(new Tuple3(this, runtimeDiagram, object), result);
-        observer.update();
+        observer.update(this, object);
     }
 
     /**
@@ -232,7 +243,7 @@ public abstract class StyleBase<Result> implements Style {
         
         final INode node = map.getNode(item);
         if (node == null) {
-            evaluationContext.update();
+            evaluationContext.update(this, item);
             // TODO: continue or return?
             return;
         }
@@ -241,7 +252,6 @@ public abstract class StyleBase<Result> implements Style {
             System.out.println(StyleBase.this + ": applying style for item " + item + " and element " + node + " with result " + value);
 
         applyStyleForNode(evaluationContext, node, value);
-        
     }
 
     /**
@@ -426,7 +436,8 @@ public abstract class StyleBase<Result> implements Style {
                 cleanupItems(observer, diagram, listener.getItems().toArray());
                 diagram = null;
             }
-            observer.update();
+            
+            //observer.update(); TODO: Check if this is required!
         }
 
     }
@@ -436,7 +447,6 @@ public abstract class StyleBase<Result> implements Style {
      */
     @Override
     public final void apply(Resource entry, Group group, final EvaluationContext evaluationContext) {
-
         ICanvasContext context = evaluationContext.getConstant(ProfileKeys.CANVAS);
         
         assert context.getThreadAccess().currentThreadAccess();
@@ -456,14 +466,41 @@ public abstract class StyleBase<Result> implements Style {
         StyleBaseData data = StyleBaseData.getInstance();
         
         data.applyRemovals(evaluationContext, this);
-        
+        IDiagram diagram = evaluationContext.getConstant(ProfileKeys.DIAGRAM);
+        assert diagram != null;
+        DataElementMap emap = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
+      
         for (Object item : listener.getItems()) {
             Result value = data.getValue(new Tuple3(this, evaluationContext.getResource(), item));
             applyStyleForItem(evaluationContext, map, item, value);
+
+            IElement element = emap.getElement(diagram, item);
+            if (element != null)
+                element.setHint(Hints.KEY_DIRTY, Hints.VALUE_SG_DIRTY);
         }
         
     }
 
+    @Override
+    public final void apply2(Object item, final EvaluationContext evaluationContext) {
+        final DataNodeMap map = evaluationContext.getConstant(ProfileKeys.NODE_MAP);
+        
+        StyleBaseData data = StyleBaseData.getInstance();
+        
+        data.applyRemovals(evaluationContext, this);
+
+        Result value = data.getValue(new Tuple3(this, evaluationContext.getResource(), item));
+        applyStyleForItem(evaluationContext, map, item, value);
+        
+        IDiagram diagram = evaluationContext.getConstant(ProfileKeys.DIAGRAM);
+        assert diagram != null;
+        DataElementMap emap = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
+        IElement element = emap.getElement(diagram, item);
+        if (element != null)
+            element.setHint(Hints.KEY_DIRTY, Hints.VALUE_SG_DIRTY);
+    }
+    
     /**
      * This is ran when this profile entry gets deactivated after being first
      * active. It allows cleaning up scene graph left-overs for the listened set
@@ -493,8 +530,16 @@ public abstract class StyleBase<Result> implements Style {
                 if (DebugPolicy.DEBUG_PROFILE_STYLE_ACTIVATION)
                     System.out.println(this + ".cleanupItems(" + evaluationContext + ", " + diagram + ", " + Arrays.toString(items));
 
+                IDiagram diagram = evaluationContext.getConstant(ProfileKeys.DIAGRAM);
+                assert diagram != null;
+                DataElementMap emap = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
+
                 for (Object item : items) {
                     cleanupStyleForItem(evaluationContext, map, item);
+
+                    IElement element = emap.getElement(diagram, item);
+                    if (element != null)
+                        element.setHint(Hints.KEY_DIRTY, Hints.VALUE_SG_DIRTY);
                 }
             }
         });
index 997ace1d63f12a87db7fc6fcaaec5f630fc92be3..c6040c0c16b4bd390cfdc67fd7a282871d403fad 100644 (file)
@@ -5,6 +5,11 @@ import java.awt.Font;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 import org.simantics.databoard.Bindings;
 import org.simantics.datatypes.literal.Vec2d;
@@ -27,6 +32,7 @@ import org.simantics.scenegraph.utils.GeometryUtils;
 import org.simantics.scenegraph.utils.NodeUtil;
 import org.simantics.scl.runtime.function.Function1;
 import org.simantics.ui.colors.Colors;
+import org.simantics.utils.datastructures.Pair;
 
 /**
  * @author Antti Villberg
@@ -149,176 +155,188 @@ public abstract class TextGridStyle extends StyleBase<MonitorTextGridResult> {
 
        @Override
        public void applyStyleForNode(EvaluationContext observer, INode _node, MonitorTextGridResult result) {
-
                String value = result != null ? result.getText1() : null;
                boolean enabled = result != null ? result.getEnabled() : false;
 
                if (value != null && enabled) {
 
-                       //        if (value != null && !value.isEmpty() && !value.trim().isEmpty()) {
-
-                       String value2 = result != null ? result.getText2() : null;
-                       String value3 = result != null ? result.getText3() : null;
-
-                       double spacing = result.getSpacing();
-
-                       final Function1<String, String> modifier = result != null ? result.getModifier() : null;
-                       final Function1<String, String> validator = result != null ? result.getValidator() : null;
-                       final Function1<Vec2d, Boolean> translator = result != null ? result.getTranslator() : null;
-                       final RVI rvi = result != null ? result.getRVI() : null;
-
-                       final TextGridNode node = ProfileVariables.claimChild(_node, "", "TextGridStyle", TextGridNode.class, observer);
-                       if (node == null)
+                       Map<String, Pair<TextGridStyle, MonitorTextGridResult>> rows = observer.getProperty(_node, "rows");
+                       if (rows == null) {
+                               rows = new HashMap<String, Pair<TextGridStyle, MonitorTextGridResult>>();
+                               observer.setProperty(_node, "rows", rows);
+                       }
+                       Pair<TextGridStyle, MonitorTextGridResult> oldResultPair = rows.get(result.getRowId());
+                       if (oldResultPair != null && oldResultPair.first == this && oldResultPair.second.sameStructure(result)) {
                                return;
-
-                       // This assumes that this TextGridStyle instance will be devoted to
-                       // this row ID until the end of its life.
-//                     String id = result.getRowId();
-//                     System.out.println(this + " ID: " + id);
-//                     if (!id.equals(this.id)) {
-//                             System.out.println(this + " SET ID: " + this.id + " -> " + id);
-//                             this.id = id;
-//                     }
-
-                       Integer newRow = observer.getTemporaryProperty(_node, "location");
-                       if (newRow == null)
-                               newRow = 1;
-
-                       // Remove from existing row to add to another row if necessary.
-                       Integer row = getCurrentRowNumber(observer, _node);
-                       if (row != null && row != newRow) {
-                               String actualId = node.getRowId(row);
-                               String id = observer.getProperty(_node, rowIdKey());
-                               if (id.equals(actualId)) {
-                                       node.removeRow(row);
-                               }
                        }
-                       row = newRow;
 
-                       node.setRowId(row, result.getRowId());
+                       rows.put(rowIdKey(), new Pair<TextGridStyle, MonitorTextGridResult>(this, result));
 
-                       setCurrentRowNumber(observer, _node, result.getRowId(), row);
+                       // FIXME: Improve performance by calling refreshAll only once after all text grid style changes have been applied
+                       refreshAll(observer, _node);
+               } else {
+                       cleanupStyleForNode(observer, _node);
+               }
+       }
 
-                       observer.setTemporaryProperty(_node, "location", row + 1);
+       private static final Comparator<Pair<TextGridStyle, MonitorTextGridResult>> ROW_PRIORITY_COMPARATOR =
+                       (o1, o2) -> Double.compare(o1.first.getPriority(), o2.first.getPriority());
 
-                       node.setText(2, row, value2);
-                       node.setUp(result.getUp());
+       private static void refreshAll(EvaluationContext observer, INode _node) {
+               final TextGridNode node = ProfileVariables.claimChild(_node, "", "TextGridStyle", TextGridNode.class, observer);
+               if (node == null)
+                       return;
 
-                       MonitorTextGridResult cache = node.getCache(1, row);
-                       if(cache != null && cache.sameStructure(result)) return;
+               int row = 0;
+               Map<String, Pair<TextGridStyle, MonitorTextGridResult>> rows = observer.getProperty(_node, "rows");
+               if (rows != null) {
+                       List<Pair<TextGridStyle, MonitorTextGridResult>> sortedRows = rows.values().stream()
+                               .sorted(ROW_PRIORITY_COMPARATOR)
+                               .collect(Collectors.toList());
 
-                       node.setCache(1, row, result);
+                       for (Pair<TextGridStyle, MonitorTextGridResult> resultPair : sortedRows) {
+                               row++;
+                               TextGridStyle style = resultPair.first;
+                               MonitorTextGridResult result = resultPair.second;
 
-                       boolean isConnection = _node instanceof ConnectionNode;
+                               String value = result != null ? result.getText1() : null;
+                               String value2 = result != null ? result.getText2() : null;
+                               String value3 = result != null ? result.getText3() : null;
 
-                       Rectangle2D elementBounds = isConnection ? EMPTY_BOUNDS : NodeUtil.getLocalElementBounds(_node);
-                       if(elementBounds == null) {
-                               new Exception("Cannot get local element bounds for node " + _node.toString()).printStackTrace();
-                               // This is here for checking why getLocalElementBounds failed in the debugger.
-                               NodeUtil.getLocalElementBounds(_node);
-                               return;
-                       }
+                               double spacing = result.getSpacing();
 
-                       //            System.err.println("elementBounds " + elementBounds);
-                       //            System.err.println("parentTransform " + result.getParentTransform());
-
-                       AffineTransform at = getTransform(_node,result.getParentTransform(), elementBounds, row, result.getUp());
-                       Vec2d offset = result.getOffset();
-
-                       Point2D[] cellOffsets = getCellOffsets();
-
-                       AffineTransform at1 = new AffineTransform(at);
-                       at1.translate(cellOffsets[0].getX(),cellOffsets[0].getY());
-                       AffineTransform at2 = new AffineTransform(at);
-                       at2.translate(cellOffsets[1].getX()+spacing,cellOffsets[1].getY());
-                       AffineTransform at3 = new AffineTransform(at);
-                       at3.translate(cellOffsets[2].getX()+spacing,cellOffsets[2].getY());
-
-                       at1.translate(offset.x, offset.y);
-                       at2.translate(offset.x, offset.y);
-                       at3.translate(offset.x, offset.y);
-
-                       node.setTransform(1, row, at1);
-                       node.setTransform(2, row, at2);
-                       node.setTransform(3, row, at3);
-
-                       Alignment[] alignments = result.getAlignments();
-                       if(alignments != null) {
-                               node.setHorizontalAlignment(1, row, (byte) alignments[0].ordinal());
-                               node.setHorizontalAlignment(2, row, (byte) alignments[1].ordinal());
-                               node.setHorizontalAlignment(3, row, (byte) alignments[2].ordinal());
-                       } else {
-                               node.setHorizontalAlignment(1, row, (byte) getAlignment(1).ordinal());
-                               node.setHorizontalAlignment(2, row, (byte) getAlignment(2).ordinal());
-                               node.setHorizontalAlignment(3, row, (byte) getAlignment(3).ordinal());
-                       }
+                               final Function1<String, String> modifier = result != null ? result.getModifier() : null;
+                               final Function1<String, String> validator = result != null ? result.getValidator() : null;
+                               final Function1<Vec2d, Boolean> translator = result != null ? result.getTranslator() : null;
+                               final RVI rvi = result != null ? result.getRVI() : null;
 
-                       Alignment[] verticalAlignments = result.getVerticalAlignments();
-                       if(verticalAlignments != null) {
-                               node.setVerticalAlignment(1, row, (byte) verticalAlignments[0].ordinal());
-                               node.setVerticalAlignment(2, row, (byte) verticalAlignments[1].ordinal());
-                               node.setVerticalAlignment(3, row, (byte) verticalAlignments[2].ordinal());
-                       } else {
-                               node.setVerticalAlignment(1, row, (byte) getVerticalAlignment(1).ordinal());
-                               node.setVerticalAlignment(2, row, (byte) getVerticalAlignment(2).ordinal());
-                               node.setVerticalAlignment(3, row, (byte) getVerticalAlignment(3).ordinal());
-                       }
+                               node.setRowId(row, result.getRowId());
 
-                       node.setZIndex(3000);
+                               //setCurrentRowNumber(observer, _node, result.getRowId(), row);
 
-                       org.simantics.common.color.Color color = result.getColor();
-                       Color awtColor = color != null ? Colors.awt(color) : Color.DARK_GRAY;
-                       Color bgColor = getBackgroundColor();
-                       Font font = getFont();
+                               //observer.setTemporaryProperty(_node, "location", row + 1);
 
-                       setTextNodeData(node, 1, row, value, font, awtColor, bgColor);
-                       setTextNodeData(node, 2, row, value2, result.getPending(), font, awtColor, bgColor);
-                       setTextNodeData(node, 3, row, value3, font, awtColor, bgColor);
+                               node.setText(2, row, value2);
+                               node.setUp(result.getUp());
 
-                       node.setEditable(1, row, false);
-                       node.setForceEventListening(2, row, true);
-                       node.setEditable(2, row, modifier != null);
-                       node.setEditable(3, row, false);
+                               //MonitorTextGridResult cache = node.getCache(1, row);
+                               //if(cache != null && cache.sameStructure(result)) return;
 
-                       final int finalRow = row;
+                               node.setCache(1, row, result);
 
-                       if (modifier != null) {
-                               node.setTextListener(2, row, new ITextListener() {
-                                       @Override
-                                       public void textChanged() {}
+                               boolean isConnection = _node instanceof ConnectionNode;
 
-                                       @Override
-                                       public void textEditingStarted() {}
+                               Rectangle2D elementBounds = isConnection ? EMPTY_BOUNDS : NodeUtil.getLocalElementBounds(_node);
+                               if (elementBounds == null) {
+                                       new Exception("Cannot get local element bounds for node " + _node.toString()).printStackTrace();
+                                       // This is here for checking why getLocalElementBounds failed in the debugger.
+                                       NodeUtil.getLocalElementBounds(_node);
+                                       return;
+                               }
+        
+                               //System.err.println("elementBounds " + elementBounds);
+                               //System.err.println("parentTransform " + result.getParentTransform());
+
+                               AffineTransform at = style.getTransform(_node,result.getParentTransform(), elementBounds, row, result.getUp());
+                               Vec2d offset = result.getOffset();
+
+                               Point2D[] cellOffsets = style.getCellOffsets();
+
+                               AffineTransform at1 = new AffineTransform(at);
+                               at1.translate(cellOffsets[0].getX(),cellOffsets[0].getY());
+                               AffineTransform at2 = new AffineTransform(at);
+                               at2.translate(cellOffsets[1].getX()+spacing,cellOffsets[1].getY());
+                               AffineTransform at3 = new AffineTransform(at);
+                               at3.translate(cellOffsets[2].getX()+spacing,cellOffsets[2].getY());
+
+                               at1.translate(offset.x, offset.y);
+                               at2.translate(offset.x, offset.y);
+                               at3.translate(offset.x, offset.y);
+
+                               node.setTransform(1, row, at1);
+                               node.setTransform(2, row, at2);
+                               node.setTransform(3, row, at3);
+
+                               Alignment[] alignments = result.getAlignments();
+                               if(alignments != null) {
+                                       node.setHorizontalAlignment(1, row, (byte) alignments[0].ordinal());
+                                       node.setHorizontalAlignment(2, row, (byte) alignments[1].ordinal());
+                                       node.setHorizontalAlignment(3, row, (byte) alignments[2].ordinal());
+                               } else {
+                                       node.setHorizontalAlignment(1, row, (byte) style.getAlignment(1).ordinal());
+                                       node.setHorizontalAlignment(2, row, (byte) style.getAlignment(2).ordinal());
+                                       node.setHorizontalAlignment(3, row, (byte) style.getAlignment(3).ordinal());
+                               }
 
-                                       @Override
-                                       public void textEditingCancelled() {
-                                       }
+                               Alignment[] verticalAlignments = result.getVerticalAlignments();
+                               if(verticalAlignments != null) {
+                                       node.setVerticalAlignment(1, row, (byte) verticalAlignments[0].ordinal());
+                                       node.setVerticalAlignment(2, row, (byte) verticalAlignments[1].ordinal());
+                                       node.setVerticalAlignment(3, row, (byte) verticalAlignments[2].ordinal());
+                               } else {
+                                       node.setVerticalAlignment(1, row, (byte) style.getVerticalAlignment(1).ordinal());
+                                       node.setVerticalAlignment(2, row, (byte) style.getVerticalAlignment(2).ordinal());
+                                       node.setVerticalAlignment(3, row, (byte) style.getVerticalAlignment(3).ordinal());
+                               }
 
-                                       @Override
-                                       public void textEditingEnded() {
+                               node.setZIndex(3000);
+        
+                               org.simantics.common.color.Color color = result.getColor();
+                               Color awtColor = color != null ? Colors.awt(color) : Color.DARK_GRAY;
+                               Color bgColor = style.getBackgroundColor();
+                               Font font = style.getFont();
+                               style.setTextNodeData(node, 1, row, value, font, awtColor, bgColor);
+                               style.setTextNodeData(node, 2, row, value2, result.getPending(), font, awtColor, bgColor);
+                               style.setTextNodeData(node, 3, row, value3, font, awtColor, bgColor);
+
+                               node.setEditable(1, row, false);
+                               node.setForceEventListening(2, row, true);
+                               node.setEditable(2, row, modifier != null);
+                               node.setEditable(3, row, false);
+
+                               final int finalRow = row;
+
+                               if (modifier != null) {
+                                       node.setTextListener(2, row, new ITextListener() {
+                                               @Override
+                                               public void textChanged() {}
+
+                                               @Override
+                                               public void textEditingStarted() {}
+
+                                               @Override
+                                               public void textEditingCancelled() {
+                                               }
+
+                                               @Override
+                                               public void textEditingEnded() {
+
+                                                       TextNode t = node.get(2, finalRow);
+                                                       if (t == null)
+                                                               return;
+
+                                                       if(!t.getText().equals(t.getTextBeforeEdit()))
+                                                               modifier.apply(t.getText());
+
+                                               }
+                                       });
+                               } else {
+                                       node.setTextListener(2, row, null);
+                               }
 
-                                               TextNode t = node.get(2, finalRow);
-                                               if (t == null)
-                                                       return;
+                               node.setInputValidator(2, row, validator);
+                               node.setTranslator(translator);
 
-                                               if(!t.getText().equals(t.getTextBeforeEdit()))
-                                                       modifier.apply(t.getText());
+                               node.setRVI(2, row, rvi);
 
-                                       }
-                               });
-                       } else {
-                               node.setTextListener(2,  row,  null);
+                               style.postProcessNode(node, row);
                        }
-
-                       node.setInputValidator(2, row, validator);
-                       node.setTranslator(translator);
-
-                       node.setRVI(2, row, rvi);
-
-                       postProcessNode(node, row);
-
-               } else {
-                       cleanupStyleForNode(observer, _node);
+               }
+               // remove excess rows
+               int rowCount = node.computeRows();
+               while (row < rowCount) {
+                       row++;
+                       node.removeRow(row);
                }
        }
 
@@ -362,38 +380,14 @@ public abstract class TextGridStyle extends StyleBase<MonitorTextGridResult> {
 
        @Override
        protected void cleanupStyleForNode(EvaluationContext observer, INode _node) {
-               Integer row = getCurrentRowNumber(observer, _node);
-               //System.out.println(this + " cleanup(" + id + ", " + row + ")");
-               //System.out.println(element);
-               if (row == null)
-                       return;
-               clearCurrentRowNumber(observer, _node);
-               TextGridNode node = ProfileVariables.browseChild(_node, "TextGridStyle");
-               if (node != null)
-                       node.removeRow(row);
-       }
-
-       private Integer getCurrentRowNumber(EvaluationContext observer, INode _node) {
-               String rowId = observer.getProperty(_node, rowIdKey());
-               return observer.getProperty(_node, rowId);
-       }
-
-       private void setCurrentRowNumber(EvaluationContext observer, INode _node, String rowId, int row) {
-               // Mapping style identity -> rowId (resourceId)
-               observer.setProperty(_node, rowIdKey(), rowId);
-               // Mapping rowId (resourceId) -> row number
-               observer.setProperty(_node, rowId, row);
-       }
-
-       private void clearCurrentRowNumber(EvaluationContext observer, INode _node) {
-               String rowId = observer.getProperty(_node, rowIdKey());
-               if(rowId != null) {
-                       observer.setProperty(_node, rowIdKey(), null);
-                       Integer row = observer.getProperty(_node, rowId);
-                       if(row != null) {
-                               observer.setProperty(_node, rowId, null);
+               Map<String, Pair<Double, MonitorTextGridResult>> rows = observer.getProperty(_node, "rows");
+               if (rows != null) {
+                       rows.remove(rowIdKey());
+                       if (rows.isEmpty()) {
+                               observer.setProperty(_node, "rows", null);
                        }
                }
+               refreshAll(observer, _node);
        }
 
        protected void postProcessNode(TextGridNode node, int row) {
index 48dce8fd2b271d78b96a8348d22bf7b466c1a735..34343870af2001e5b143978c78bd0d2fb6167a4c 100644 (file)
@@ -25,6 +25,12 @@ public interface Observer {
      * requesting for style re-application for the whole diagram.
      */
     void update();
+    
+    /**
+     * Notifies this profile system instance that a profile subsystem is
+     * requesting for style re-application for the given item.
+     */
+    void update(Style style, Object item);
 
     /**
      * For logging exceptional situations that occur within profile entries or
index c719df2d7aaf862afa12b9dee67aeee6b7b3fa2b..4eecce9fc09d33421c8779968f4daec6c715fb00 100644 (file)
@@ -66,5 +66,8 @@ public interface Style {
      * @param observer profile system observer for this canvas context
      */
     void apply(Resource entry, Group group, EvaluationContext observer);
-
+    
+    void apply2(Object item, EvaluationContext observer);
+    void setPriority(double priority);
+    double getPriority();
 }
index efac19055944c8a2ab3bc713dd3100647755d9f8..9d379c890b9bd952a3ac2b6db941b3c71acc07c6 100644 (file)
  *******************************************************************************/
 package org.simantics.scenegraph.profile.common;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
@@ -28,9 +30,11 @@ import org.simantics.scenegraph.INode;
 import org.simantics.scenegraph.g2d.G2DSceneGraph;
 import org.simantics.scenegraph.profile.EvaluationContext;
 import org.simantics.scenegraph.profile.ProfileEntry;
+import org.simantics.scenegraph.profile.Style;
 import org.simantics.scenegraph.profile.impl.DebugPolicy;
 import org.simantics.scenegraph.profile.impl.ProfileActivationListener;
 import org.simantics.scenegraph.profile.request.RuntimeProfileActiveEntries;
+import org.simantics.utils.datastructures.Pair;
 import org.simantics.utils.datastructures.disposable.IDisposable;
 import org.simantics.utils.threads.IThreadWorkQueue;
 import org.simantics.utils.threads.ThreadUtils;
@@ -51,9 +55,12 @@ public class ProfileObserver implements EvaluationContext {
     private final Runnable                    notification;
     private final G2DSceneGraph               sceneGraph;
 
-    private boolean                           dirty               = true;
-    private boolean                           disposed            = false;
+    private volatile boolean                  dirty               = true;
+    private volatile boolean                  disposed            = false;
 
+    private List<Pair<Style, Object>>         updates             = new ArrayList<>();
+    private boolean                           updateAll;
+    
     private ProfileActivationListener         activationListener;
 
     private Map<String, Object>               constants           = new HashMap<String, Object>();
@@ -129,12 +136,20 @@ public class ProfileObserver implements EvaluationContext {
     }
 
     @Override
-    public void update() {
+    public void update(Style style, Object item) {
         if (DebugPolicy.DEBUG_PROFILE_OBSERVER_UPDATE)
             System.out.println("Profile observer marked dirty.");
+        
+        updates.add(Pair.make(style, item));
+        //updateAll = true;
         dirty = true;
     }
 
+    public void update() {
+        updateAll = true;
+        dirty = true;
+    }
+    
     private void perform() {
         dirty = false;
         if (DebugPolicy.DEBUG_PROFILE_OBSERVER_UPDATE)
@@ -148,39 +163,39 @@ public class ProfileObserver implements EvaluationContext {
                     return;
 
                 ThreadUtils.asyncExec(thread, new Runnable() {
-                    
-//                    private void init(INode node) {
-//                        //ProfileVariables.init(node, ProfileObserver.this);
-////                        NodeUtil.forChildren(node, new NodeProcedure<Object>() {
-////                            @Override
-////                            public Object execute(INode node, String id) {
-////                                init(node);
-////                                return null;
-////                            }
-////                        }, null);
-//                    }
-
                     @Override
                     public void run() {
-
                         if (isDisposed())
                             return;
 
                         temporaryProperties.clear();
 
-//                        init(sceneGraph);
-
-//                        for(IElement e : diagram.getElements()) {
-//                            Node node = NodeUtils.
-//                            Variables.init(e, ProfileObserver.this);
-//                        }
-
-                        for(ProfileEntry e : entries) {
-                            if (DebugPolicy.DEBUG_PROFILE_OBSERVER_PERFORM)
-                                System.out.println("Apply profile entry: " + e);
-                            e.apply(ProfileObserver.this);
+                        long t0 = DebugPolicy.DEBUG_PROFILE_OBSERVER_PERFORM ? System.nanoTime() : 0L;
+                        
+                        if (updateAll) {
+                            for(ProfileEntry e : entries) {
+                                if (DebugPolicy.DEBUG_PROFILE_OBSERVER_PERFORM)
+                                    System.out.println("Apply profile entry: " + e);
+                                e.apply(ProfileObserver.this);
+                            }
+                            updateAll = false;
+                            updates.clear();
+                        } else {
+                            List<Pair<Style, Object>> updatesCopy = new ArrayList<>(updates);
+                            updates.clear();
+                            for (Pair<Style, Object> update : updatesCopy) {
+                                Style style = update.first;
+                                Object item = update.second;
+                                
+                                style.apply2(item, ProfileObserver.this);
+                            }
                         }
 
+                        if (DebugPolicy.DEBUG_PROFILE_OBSERVER_PERFORM) {
+                            long t1 = System.nanoTime();
+                            System.out.println((t1-t0) / 1e6);
+                        }
+                        
                         if(dirty) {
                                sceneGraph.setPending(ProfileObserver.this);
 //                             System.err.println("setPending, dirty=true");
@@ -194,21 +209,12 @@ public class ProfileObserver implements EvaluationContext {
 //                        canvas.getContentContext().setDirty();
                         
                         // Something is underway, schedule update
-                        if(dirty) {
-                               Simantics.async(new Runnable() {
-
-                                                               @Override
-                                                               public void run() {
-
-                                                           if (isDisposed()) return;
-                                                           
-                                                                       if(dirty) perform();
-                                                                       
-                                                               }
-                                       
-                               }, 100, TimeUnit.MILLISECONDS);
+                        if (dirty) {
+                            Simantics.async(() -> {
+                                if (isDisposed()) return;
+                                if (dirty) perform();
+                            }, 100, TimeUnit.MILLISECONDS);
                         }
-
                     }
                 });
             }