]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.diagram/src/org/simantics/diagram/profile/StyleBase.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / profile / StyleBase.java
index 21071ba74bd9453e9c3bdf166c0240bd46156c54..fee1e8546d7e96e07bf13a21f53b98f26afac6c4 100644 (file)
  *******************************************************************************/
 package org.simantics.diagram.profile;
 
-import java.util.ArrayList;
 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;
@@ -32,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;
@@ -44,8 +41,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.scl.runtime.tuple.Tuple;
-import org.simantics.scl.runtime.tuple.Tuple2;
+import org.simantics.scl.runtime.tuple.Tuple3;
 import org.simantics.utils.datastructures.Pair;
 
 /**
@@ -72,14 +68,58 @@ import org.simantics.utils.datastructures.Pair;
  */
 public abstract class StyleBase<Result> implements Style {
 
-    protected final Map<Tuple, Result> values   = new ConcurrentHashMap<Tuple, Result>();
+    private Object identity;
+    private double priority;
 
-//    private Map<Resource,ObserverGroupListener>         listeners = new ConcurrentHashMap<Resource, ObserverGroupListener>();
+    public StyleBase(Object identity) {
+        this.identity = identity;
+    }
+
+    public StyleBase() {
+        this.identity = getClass();
+    }
+
+    @SuppressWarnings("unchecked")
+    protected <T> T getIdentity() {
+        return (T)identity;
+    }
 
-    private Map<Pair<Resource, Group>, ObserverGroupListener> listeners = new HashMap<Pair<Resource, Group>, ObserverGroupListener>();
+    public void setPriority(double priority) {
+        this.priority = priority;
+    }
+    
+    public double getPriority() {
+        return priority;
+    }
     
+    @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;
+    }
 
-    private final List<Resource>                removals = new ArrayList<Resource>();
+    protected Resource getResource() {
+        return getIdentity();
+    }
 
     /**
      * For caching this simple base request that is done in every
@@ -175,10 +215,10 @@ public abstract class StyleBase<Result> implements Style {
      */
     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
-            values.put(new Tuple2(runtimeDiagram, object), result);
-        observer.update();
+            StyleBaseData.getInstance().putValue(new Tuple3(this, runtimeDiagram, object), result);
+        observer.update(this, object);
     }
 
     /**
@@ -203,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;
         }
@@ -212,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);
-        
     }
 
     /**
@@ -283,9 +322,7 @@ public abstract class StyleBase<Result> implements Style {
               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);
@@ -308,7 +345,7 @@ public abstract class StyleBase<Result> implements Style {
 
             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);
 
@@ -390,7 +427,7 @@ public abstract class StyleBase<Result> implements Style {
             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!
@@ -399,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!
         }
 
     }
@@ -409,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();
@@ -425,24 +462,45 @@ 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 (!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);
+        IDiagram diagram = evaluationContext.getConstant(ProfileKeys.DIAGRAM);
+        assert diagram != null;
+        DataElementMap emap = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
+      
         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);
+
+            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
@@ -472,15 +530,23 @@ 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);
                 }
             }
         });
     }
     
     private ObserverGroupListener getListener(Resource runtime, Group group) {
-        return listeners.get(Pair.make(runtime, group));
+        return StyleBaseData.getInstance().getListener(new Tuple3(this, runtime, group));
     }
 
 }