]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
Fix diagram profiles to work with latest DB changes 41/2241/5
authorAntti Villberg <antti.villberg@semantum.fi>
Wed, 26 Sep 2018 04:53:54 +0000 (06:53 +0200)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Wed, 26 Sep 2018 08:47:37 +0000 (08:47 +0000)
gitlab #96

Change-Id: I799c1f22422126290aed0868d6fe4ceed6bccaa9

bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/TypeGroup.java
bundles/org.simantics.diagram/src/org/simantics/diagram/profile/ResourceSCLTextGridStyle.java
bundles/org.simantics.diagram/src/org/simantics/diagram/profile/SCLTextGridStyle.java
bundles/org.simantics.diagram/src/org/simantics/diagram/profile/StyleBase.java
bundles/org.simantics.diagram/src/org/simantics/diagram/profile/StyleBaseData.java [new file with mode: 0644]
bundles/org.simantics.diagram/src/org/simantics/diagram/profile/TextGridStyle.java

index e025fb2ddf16927783a2fc353817b87c9c068155..b7b4ba2ff13bb9d9a55fec7a155bbc389bdd8883 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
 /*******************************************************************************
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * Copyright (c) 2007, 2018 Association for Decentralized Information Management
  * in Industry THTH ry.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * in Industry THTH ry.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -39,7 +39,7 @@ public class TypeGroup implements Group {
     private final String               name;
 
     public TypeGroup(String name, Resource type) {
     private final String               name;
 
     public TypeGroup(String name, Resource type) {
-        this(name);
+        this(name, new Resource[] { type });
     }
 
     public TypeGroup(String name, Resource... types) {
     }
 
     public TypeGroup(String name, Resource... types) {
@@ -47,6 +47,26 @@ public class TypeGroup implements Group {
         this.name = name;
     }
 
         this.name = name;
     }
 
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + types.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;
+        TypeGroup other = (TypeGroup) obj;
+        return types.equals(other.types);
+    }
+
     /**
      * Initialize TypeGroup from a DIAGRAM.Group instance.
      * 
     /**
      * Initialize TypeGroup from a DIAGRAM.Group instance.
      * 
index 3bbbf8081dea77cfbb7792d0c1ecbd97d3e2a1ed..c9a83ff8b087a9d801ad0bbfa96a664edefc2e95 100644 (file)
@@ -23,13 +23,12 @@ import org.simantics.utils.datastructures.Pair;
  */
 public class ResourceSCLTextGridStyle extends TextGridStyle {
 
  */
 public class ResourceSCLTextGridStyle extends TextGridStyle {
 
-       final Resource style;
        final Font font;
 
        public ResourceSCLTextGridStyle(ReadGraph graph, Resource style) throws DatabaseException {
        final Font font;
 
        public ResourceSCLTextGridStyle(ReadGraph graph, Resource style) throws DatabaseException {
-               this.style = style;
+               super(style);
                G2DResource G2D = G2DResource.getInstance(graph);
                G2DResource G2D = G2DResource.getInstance(graph);
-        Resource fontR = graph.getPossibleObject(style, G2D.HasFont);
+               Resource fontR = graph.getPossibleObject(style, G2D.HasFont);
                if(fontR != null) {
                        font = G2DUtils.getFont(graph, fontR);
                } else {
                if(fontR != null) {
                        font = G2DUtils.getFont(graph, fontR);
                } else {
@@ -51,7 +50,7 @@ public class ResourceSCLTextGridStyle extends TextGridStyle {
 
        @Override
        protected Object getIdentity(Resource entry) {
 
        @Override
        protected Object getIdentity(Resource entry) {
-               return new Pair<Resource, Resource>(style, entry);
+               return new Pair<Resource, Resource>(getResource(), entry);
        }
 
        @Override
        }
 
        @Override
@@ -63,10 +62,10 @@ public class ResourceSCLTextGridStyle extends TextGridStyle {
        public MonitorTextGridResult calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration) throws DatabaseException {
                DiagramResource DIA = DiagramResource.getInstance(graph);
 
        public MonitorTextGridResult calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration) throws DatabaseException {
                DiagramResource DIA = DiagramResource.getInstance(graph);
 
-               Variable styleVariable = Variables.getVariable(graph, style);
+               Variable styleVariable = Variables.getVariable(graph, getResource());
                Function1<Resource,Tuple3> function = styleVariable.getPossiblePropertyValue(graph, DIA.ResourceSCLTextGridStyle_texts);
                Tuple3 result = Simantics.applySCLRead(graph, function, element);
                Function1<Resource,Tuple3> function = styleVariable.getPossiblePropertyValue(graph, DIA.ResourceSCLTextGridStyle_texts);
                Tuple3 result = Simantics.applySCLRead(graph, function, element);
-               
+
                AffineTransform transform = DiagramGraphUtil.getAffineTransform(graph, element);
                Vec2d offset = DiagramGraphUtil.getOffset(graph, element);
                boolean enabled = !DiagramGraphUtil.getProfileMonitorsHidden(graph, element);
                AffineTransform transform = DiagramGraphUtil.getAffineTransform(graph, element);
                Vec2d offset = DiagramGraphUtil.getOffset(graph, element);
                boolean enabled = !DiagramGraphUtil.getProfileMonitorsHidden(graph, element);
@@ -79,7 +78,7 @@ public class ResourceSCLTextGridStyle extends TextGridStyle {
 
        @Override
        public String getNodeName() {
 
        @Override
        public String getNodeName() {
-               return "" + style.getResourceId();
+               return "" + getResource().getResourceId();
        }
 
 }
        }
 
 }
index 4401f2213c51aa0a58b0b0c8170ab5e9636d281c..16b205388733c0ba5f3d86fea0b22b6781632012 100644 (file)
@@ -25,13 +25,12 @@ import org.simantics.utils.datastructures.Pair;
  */
 public class SCLTextGridStyle extends TextGridStyle {
 
  */
 public class SCLTextGridStyle extends TextGridStyle {
 
-       final Resource style;
        final Font font;
 
        public SCLTextGridStyle(ReadGraph graph, Resource style) throws DatabaseException {
        final Font font;
 
        public SCLTextGridStyle(ReadGraph graph, Resource style) throws DatabaseException {
-               this.style = style;
+               super(style);
                G2DResource G2D = G2DResource.getInstance(graph);
                G2DResource G2D = G2DResource.getInstance(graph);
-        Resource fontR = graph.getPossibleObject(style, G2D.HasFont);
+               Resource fontR = graph.getPossibleObject(style, G2D.HasFont);
                if(fontR != null) {
                        font = G2DUtils.getFont(graph, fontR);
                } else {
                if(fontR != null) {
                        font = G2DUtils.getFont(graph, fontR);
                } else {
@@ -53,7 +52,7 @@ public class SCLTextGridStyle extends TextGridStyle {
 
        @Override
        protected Object getIdentity(Resource entry) {
 
        @Override
        protected Object getIdentity(Resource entry) {
-               return new Pair<Resource, Resource>(style, entry);
+               return new Pair<Resource, Resource>(getResource(), entry);
        }
 
        @Override
        }
 
        @Override
@@ -81,7 +80,7 @@ public class SCLTextGridStyle extends TextGridStyle {
                if (moduleVariable == null)
                        return null;
 
                if (moduleVariable == null)
                        return null;
 
-               Variable styleVariable = Variables.getVariable(graph, style);
+               Variable styleVariable = Variables.getVariable(graph, getResource());
                Function1<Variable,Tuple3> function = styleVariable.getPossiblePropertyValue(graph, DIA.SCLTextGridStyle_texts);
                Tuple3 result = Simantics.applySCLRead(graph, function, moduleVariable);
                
                Function1<Variable,Tuple3> function = styleVariable.getPossiblePropertyValue(graph, DIA.SCLTextGridStyle_texts);
                Tuple3 result = Simantics.applySCLRead(graph, function, moduleVariable);
                
@@ -97,7 +96,7 @@ public class SCLTextGridStyle extends TextGridStyle {
 
        @Override
        public String getNodeName() {
 
        @Override
        public String getNodeName() {
-               return "" + style.getResourceId();
+               return "" + getResource().getResourceId();
        }
 
 }
        }
 
 }
index 21071ba74bd9453e9c3bdf166c0240bd46156c54..e1d8b1fbf7e67e043c8af93202f03d95747d9216 100644 (file)
  *******************************************************************************/
 package org.simantics.diagram.profile;
 
  *******************************************************************************/
 package org.simantics.diagram.profile;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
 
 import org.simantics.databoard.Bindings;
 import org.simantics.db.ReadGraph;
 
 import org.simantics.databoard.Bindings;
 import org.simantics.db.ReadGraph;
@@ -44,8 +39,7 @@ import org.simantics.scenegraph.profile.Style;
 import org.simantics.scenegraph.profile.common.ObserverGroupListener;
 import org.simantics.scenegraph.profile.common.ObserverGroupValueListener;
 import org.simantics.scenegraph.profile.impl.DebugPolicy;
 import org.simantics.scenegraph.profile.common.ObserverGroupListener;
 import org.simantics.scenegraph.profile.common.ObserverGroupValueListener;
 import org.simantics.scenegraph.profile.impl.DebugPolicy;
-import org.simantics.scl.runtime.tuple.Tuple;
-import org.simantics.scl.runtime.tuple.Tuple2;
+import org.simantics.scl.runtime.tuple.Tuple3;
 import org.simantics.utils.datastructures.Pair;
 
 /**
 import org.simantics.utils.datastructures.Pair;
 
 /**
@@ -72,14 +66,48 @@ import org.simantics.utils.datastructures.Pair;
  */
 public abstract class StyleBase<Result> implements Style {
 
  */
 public abstract class StyleBase<Result> implements Style {
 
-    protected final Map<Tuple, Result> values   = new ConcurrentHashMap<Tuple, Result>();
+    private Object identity;
 
 
-//    private Map<Resource,ObserverGroupListener>         listeners = new ConcurrentHashMap<Resource, ObserverGroupListener>();
+    public StyleBase(Object identity) {
+        this.identity = identity;
+    }
 
 
-    private Map<Pair<Resource, Group>, ObserverGroupListener> listeners = new HashMap<Pair<Resource, Group>, ObserverGroupListener>();
-    
+    public StyleBase() {
+        this.identity = getClass();
+    }
 
 
-    private final List<Resource>                removals = new ArrayList<Resource>();
+    protected <T> T getIdentity() {
+        return (T)identity;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((identity == null) ? 0 : identity.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;
+        StyleBase other = (StyleBase) obj;
+        if (identity == null) {
+            if (other.identity != null)
+                return false;
+        } else if (!identity.equals(other.identity))
+            return false;
+        return true;
+    }
+
+    protected Resource getResource() {
+        return getIdentity();
+    }
 
     /**
      * For caching this simple base request that is done in every
 
     /**
      * For caching this simple base request that is done in every
@@ -175,9 +203,9 @@ public abstract class StyleBase<Result> implements Style {
      */
     public void styleResultChanged(Observer observer, Resource runtimeDiagram, Resource object, Result result) {
         if (result == null)
      */
     public void styleResultChanged(Observer observer, Resource runtimeDiagram, Resource object, Result result) {
         if (result == null)
-            values.remove(new Tuple2(runtimeDiagram, object));
+            StyleBaseData.getInstance().removeValue(new Tuple3(this, runtimeDiagram, object));
         else
         else
-            values.put(new Tuple2(runtimeDiagram, object), result);
+            StyleBaseData.getInstance().putValue(new Tuple3(this, runtimeDiagram, object), result);
         observer.update();
     }
 
         observer.update();
     }
 
@@ -283,9 +311,7 @@ public abstract class StyleBase<Result> implements Style {
               if (DebugPolicy.DEBUG_PROFILE_STYLE_GROUP_TRACKING)
                   System.out.println(style + ": removed from group " + group + ": " + item);
 
               if (DebugPolicy.DEBUG_PROFILE_STYLE_GROUP_TRACKING)
                   System.out.println(style + ": removed from group " + group + ": " + item);
 
-              synchronized (style.removals) {
-                 style.removals.add(item);
-              }
+              StyleBaseData.getInstance().removeItem(style, item);
 
               // TODO: do something here to dispose of ObserverGroupValueListeners?
               super.remove(item);
 
               // TODO: do something here to dispose of ObserverGroupValueListeners?
               super.remove(item);
@@ -308,7 +334,7 @@ public abstract class StyleBase<Result> implements Style {
 
             listener = new GroupListener<Result>(backend.getSession(), runtimeDiagram, entry, this, group, observer);
 
 
             listener = new GroupListener<Result>(backend.getSession(), runtimeDiagram, entry, this, group, observer);
 
-            listeners.put(Pair.make(runtimeDiagram, group), listener);
+            StyleBaseData.getInstance().putListener(new Tuple3(this, runtimeDiagram, group), listener);
 
             group.trackItems(backend, runtimeDiagram, listener);
 
 
             group.trackItems(backend, runtimeDiagram, listener);
 
@@ -390,7 +416,7 @@ public abstract class StyleBase<Result> implements Style {
             listener.removeEntry(entry);
             if (!listener.hasEntries()) {
                 listener.dispose();
             listener.removeEntry(entry);
             if (!listener.hasEntries()) {
                 listener.dispose();
-                listeners.remove(Pair.make(runtimeDiagram, group));
+                StyleBaseData.getInstance().removeListener(new Tuple3(this, runtimeDiagram, group));
             }
 
             // This was too eager when multiple groups were tracked!
             }
 
             // This was too eager when multiple groups were tracked!
@@ -425,19 +451,13 @@ public abstract class StyleBase<Result> implements Style {
         if (DebugPolicy.DEBUG_PROFILE_STYLE_APPLICATION)
             System.out.println(StyleBase.this + ": applying style for items: " + listener.getItems());
 
         if (DebugPolicy.DEBUG_PROFILE_STYLE_APPLICATION)
             System.out.println(StyleBase.this + ": applying style for items: " + listener.getItems());
 
-        if (!removals.isEmpty()) {
-            Resource[] removed;
-            synchronized (removals) {
-                removed = removals.toArray(Resource.NONE);
-                removals.clear();
-            }
-            for (Resource item : removed) {
-                cleanupStyleForItem(evaluationContext, map, item);
-            }
-        }
+        
+        StyleBaseData data = StyleBaseData.getInstance();
+        
+        data.applyRemovals(evaluationContext, this);
         
         for (Object item : listener.getItems()) {
         
         for (Object item : listener.getItems()) {
-            Result value = values.get(new Tuple2(evaluationContext.getResource(), item));
+            Result value = data.getValue(new Tuple3(this, evaluationContext.getResource(), item));
             applyStyleForItem(evaluationContext, map, item, value);
         }
         
             applyStyleForItem(evaluationContext, map, item, value);
         }
         
@@ -480,7 +500,7 @@ public abstract class StyleBase<Result> implements Style {
     }
     
     private ObserverGroupListener getListener(Resource runtime, Group group) {
     }
     
     private ObserverGroupListener getListener(Resource runtime, Group group) {
-        return listeners.get(Pair.make(runtime, group));
+        return StyleBaseData.getInstance().getListener(new Tuple3(this, runtime, group));
     }
 
 }
     }
 
 }
diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/profile/StyleBaseData.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/profile/StyleBaseData.java
new file mode 100644 (file)
index 0000000..ca97fea
--- /dev/null
@@ -0,0 +1,86 @@
+package org.simantics.diagram.profile;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.simantics.db.Resource;
+import org.simantics.scenegraph.profile.DataNodeMap;
+import org.simantics.scenegraph.profile.EvaluationContext;
+import org.simantics.scenegraph.profile.Style;
+import org.simantics.scenegraph.profile.common.ObserverGroupListener;
+import org.simantics.scl.runtime.tuple.Tuple;
+import org.simantics.scl.runtime.tuple.Tuple3;
+
+public class StyleBaseData {
+
+    private static StyleBaseData INSTANCE;
+
+    protected final Map<Tuple, Object> values   = new ConcurrentHashMap<>();
+
+    private Map<Tuple3, ObserverGroupListener> listeners = new HashMap<>();
+
+    private final Map<Style, List<Resource>> removals = new HashMap<>();
+
+    private StyleBaseData() {
+    }
+
+    public static StyleBaseData getInstance() {
+        if (INSTANCE == null) {
+            synchronized (StyleBaseData.class) {
+                if (INSTANCE == null) {
+                    INSTANCE = new StyleBaseData();
+                }
+            }
+        }
+        return INSTANCE;
+    }
+
+    public void removeValue(Tuple t) {
+        values.remove(t);
+    }
+
+    public void putValue(Tuple t, Object o) {
+        values.put(t, o);
+    }
+
+    public <T> T getValue(Tuple t) {
+        return (T) values.get(t);
+    }
+
+    public synchronized void removeItem(Style s, Resource r) {
+        List<Resource> l = removals.get(s);
+        if (l == null) {
+            l = new ArrayList<>();
+            removals.put(s, l);
+        }
+        l.add(r);
+    }
+
+    public void putListener(Tuple3 key, ObserverGroupListener listener) {
+        listeners.put(key, listener);
+    }
+
+    public void removeListener(Tuple3 key) {
+        listeners.remove(key);
+    }
+
+    public ObserverGroupListener getListener(Tuple3 key) {
+        return listeners.get(key);
+    }
+
+    public synchronized void applyRemovals(EvaluationContext evaluationContext, StyleBase s) {
+        List<Resource> rs = removals.remove(s);
+        if (rs == null)
+            return;
+
+        DataNodeMap map = evaluationContext.getConstant(ProfileKeys.NODE_MAP);
+
+        for (Resource item : rs) {
+            s.cleanupStyleForItem(evaluationContext, map, item);
+        }
+    }
+
+}
index 54972155d8d69579294e4d6e49718a453e14e66d..997ace1d63f12a87db7fc6fcaaec5f630fc92be3 100644 (file)
@@ -38,17 +38,15 @@ public abstract class TextGridStyle extends StyleBase<MonitorTextGridResult> {
        private final Color BACKGROUND_COLOR = new Color(255, 255, 255, 192);
        private static final Rectangle2D EMPTY_BOUNDS = new Rectangle2D.Double(0, 0, 0, 0);
 
        private final Color BACKGROUND_COLOR = new Color(255, 255, 255, 192);
        private static final Rectangle2D EMPTY_BOUNDS = new Rectangle2D.Double(0, 0, 0, 0);
 
-       // NOTE: this is a hack
-       String id;
-
        protected double xOffset;
        protected double yOffset;
 
        protected double xOffset;
        protected double yOffset;
 
-       public TextGridStyle() {
-               this(0.0, 2.1);
+       public TextGridStyle(Resource r) {
+               this(r, 0.0, 2.1);
        }
 
        }
 
-       public TextGridStyle(double xOffset, double yOffset) {
+       public TextGridStyle(Resource r, double xOffset, double yOffset) {
+           super(r);
                this.xOffset = xOffset;
                this.yOffset = yOffset;
        }
                this.xOffset = xOffset;
                this.yOffset = yOffset;
        }
@@ -175,29 +173,32 @@ public abstract class TextGridStyle extends StyleBase<MonitorTextGridResult> {
 
                        // This assumes that this TextGridStyle instance will be devoted to
                        // this row ID until the end of its life.
 
                        // 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;
-                       }
+//                     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 newRow = observer.getTemporaryProperty(_node, "location");
                        if (newRow == null)
                                newRow = 1;
 
                        // Remove from existing row to add to another row if necessary.
-                       Integer row = observer.getProperty(_node, id);
+                       Integer row = getCurrentRowNumber(observer, _node);
                        if (row != null && row != newRow) {
                                String actualId = node.getRowId(row);
                        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;
 
                                if (id.equals(actualId)) {
                                        node.removeRow(row);
                                }
                        }
                        row = newRow;
 
-                       node.setRowId(row, id);
-                       observer.setProperty(_node, id, row);
+                       node.setRowId(row, result.getRowId());
+
+                       setCurrentRowNumber(observer, _node, result.getRowId(), row);
+
                        observer.setTemporaryProperty(_node, "location", row + 1);
 
                        node.setText(2, row, value2);
                        observer.setTemporaryProperty(_node, "location", row + 1);
 
                        node.setText(2, row, value2);
@@ -361,18 +362,45 @@ public abstract class TextGridStyle extends StyleBase<MonitorTextGridResult> {
 
        @Override
        protected void cleanupStyleForNode(EvaluationContext observer, INode _node) {
 
        @Override
        protected void cleanupStyleForNode(EvaluationContext observer, INode _node) {
-               Integer row = observer.getProperty(_node, id);
+               Integer row = getCurrentRowNumber(observer, _node);
                //System.out.println(this + " cleanup(" + id + ", " + row + ")");
                //System.out.println(element);
                if (row == null)
                        return;
                //System.out.println(this + " cleanup(" + id + ", " + row + ")");
                //System.out.println(element);
                if (row == null)
                        return;
-               observer.setProperty(_node, id, null);
+               clearCurrentRowNumber(observer, _node);
                TextGridNode node = ProfileVariables.browseChild(_node, "TextGridStyle");
                if (node != null)
                        node.removeRow(row);
        }
 
                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);
+                       }
+               }
+       }
+
        protected void postProcessNode(TextGridNode node, int row) {
        }
 
        protected void postProcessNode(TextGridNode node, int row) {
        }
 
+       private String rowIdKey() {
+               return "style" + getIdentity().toString();
+       }
+
 }
 }