Commits

eja committed 2e2709e

Fixed bug in transaction handling of edge redirection (and thus node merging) as reported by Thomas
Added test against it

  • Participants
  • Parent commits ab828d3
  • Branches v3.0

Comments (0)

Files changed (4)

engine-net-2/src/lgspBackend/lgspTransactionManager.cs

     }
 
     ////////////////////////////////////////////////////////////////////////////////
+    public class LGSPUndoElemRedirecting : IUndoItem
+    ////////////////////////////////////////////////////////////////////////////////
+    {
+        public LGSPEdge _edge;
+        public LGSPNode _source;
+        public LGSPNode _target;
+
+        public LGSPUndoElemRedirecting(LGSPEdge edge, LGSPNode source, LGSPNode target)
+        {
+            _edge = edge;
+            _source = source;
+            _target = target;
+        }
+
+        public void DoUndo(IGraph graph)
+        {
+            _edge.lgspSource = _source;
+            _edge.lgspTarget = _target;
+        }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////////
 
     /// <summary>
     /// A class for managing graph transactions.
     public class LGSPTransactionManager : ITransactionManager
     {
         private LinkedList<IUndoItem> undoItems = new LinkedList<IUndoItem>();
+        private IEdge currentlyRedirectedEdge;
         private bool recording = false;
         private bool reuseOptimizationBackup = false;
         private bool undoing = false;
             graph.OnChangingEdgeAttribute += new ChangingEdgeAttributeHandler(ChangingElementAttribute);
             graph.OnRetypingNode += new RetypingNodeHandler(RetypingElement);
             graph.OnRetypingEdge += new RetypingEdgeHandler(RetypingElement);
+            graph.OnRedirectingEdge += RedirectingEdge;
 
             recording = true;
             reuseOptimizationBackup = graph.ReuseOptimization;
             graph.OnChangingEdgeAttribute -= new ChangingEdgeAttributeHandler(ChangingElementAttribute);
             graph.OnRetypingNode -= new RetypingNodeHandler(RetypingElement);
             graph.OnRetypingEdge -= new RetypingEdgeHandler(RetypingElement);
+            graph.OnRedirectingEdge -= RedirectingEdge;
 
             recording = false;
             graph.ReuseOptimization = reuseOptimizationBackup;
                 } else if(undoItems.Last.Value is LGSPUndoElemRetyped) {
                     LGSPUndoElemRetyped item = (LGSPUndoElemRetyped)undoItems.Last.Value;
                     writer.WriteLine("RetypingElement: " + graph.GetElementName(item._newElem) + ":" + item._newElem.Type.Name + "<" + graph.GetElementName(item._oldElem)+ ":" + item._oldElem.Type.Name + ">");
+                } else if(undoItems.Last.Value is LGSPUndoElemRedirecting) {
+                    LGSPUndoElemRedirecting item = (LGSPUndoElemRedirecting)undoItems.Last.Value;
+                    writer.WriteLine("RedirectingEdge: " + graph.GetElementName(item._edge) + " before undoing removal");
                 }
 #endif
                 undoItems.Last.Value.DoUndo(graph);
 
         public void ElementAdded(IGraphElement elem)
         {
-            if(recording && !undoing) undoItems.AddLast(new LGSPUndoElemAdded(elem));
+            if(recording && !undoing)
+                undoItems.AddLast(new LGSPUndoElemAdded(elem));
+
 #if LOG_TRANSACTION_HANDLING
             if(elem is INode) {
                 INode node = (INode)elem;
                 writer.WriteLine("RemovingElement: " + graph.GetElementName(edge.Source) + " -" + graph.GetElementName(edge) + ":" + edge.Type.Name + "-> " + graph.GetElementName(edge.Target));
             }
 #endif
-            if(recording && !undoing) undoItems.AddLast(new LGSPUndoElemRemoved(elem, graph));
+            if(recording && !undoing)
+            {
+                undoItems.AddLast(new LGSPUndoElemRemoved(elem, graph));
+                if(Object.ReferenceEquals(elem, currentlyRedirectedEdge))
+                {
+                    LGSPEdge edge = (LGSPEdge)elem;
+                    undoItems.AddLast(new LGSPUndoElemRedirecting(edge, edge.lgspSource, edge.lgspTarget));
+                    currentlyRedirectedEdge = null;
+                }
+            }
         }
 
         public void ChangingElementAttribute(IGraphElement elem, AttributeType attrType,
 #if LOG_TRANSACTION_HANDLING
             writer.WriteLine("ChangingElementAttribute: " + graph.GetElementName(elem) + ":" + elem.Type.Name + "." + attrType.Name);
 #endif
-            if(recording && !undoing) undoItems.AddLast(new LGSPUndoAttributeChanged(elem, attrType, changeType, newValue, keyValue));
+            if(recording && !undoing)
+                undoItems.AddLast(new LGSPUndoAttributeChanged(elem, attrType, changeType, newValue, keyValue));
         }
 
         public void RetypingElement(IGraphElement oldElem, IGraphElement newElem)
 #if LOG_TRANSACTION_HANDLING
             writer.WriteLine("RetypingElement: " + graph.GetElementName(newElem) + ":" + newElem.Type.Name+ "<" + graph.GetElementName(oldElem) + ":" + oldElem.Type.Name + ">");
 #endif
-            if(recording && !undoing) undoItems.AddLast(new LGSPUndoElemRetyped(oldElem, newElem));
+            if(recording && !undoing)
+                undoItems.AddLast(new LGSPUndoElemRetyped(oldElem, newElem));
+        }
+
+        public void RedirectingEdge(IEdge edge)
+        {
+#if LOG_TRANSACTION_HANDLING
+            writer.WriteLine("RedirectingEdge: " + " -" + graph.GetElementName(edge) + "-> " );
+#endif
+            if(recording && !undoing)
+                currentlyRedirectedEdge = edge;
         }
 
         public bool TransactionActive { get { return recording; } }

engine-net-2/tests/transaction/mergetransaction.grg

+rule init : (Node, Node, Node, Node)
+{
+	modify {
+		a:Node --> b:Node --> c:Node; d:Node;
+		a --> a; b --> b; 
+		return(a,b,c,d);
+	}
+}
+
+test matchinit
+{
+	a:Node --> b:Node --> c:Node; d:Node;
+	a --> a; b --> b; 
+}
+
+rule merge(a:Node, b:Node, c:Node, d:Node)
+{
+	replace {
+		m:Node<a,b,c,d>;
+	}
+}
+
+test matchmerge
+{
+	m:Node;
+	m --> m;
+	m --> m;
+	m --> m;
+	m --> m;
+}
+

engine-net-2/tests/transaction/mergetransaction.grs

+new graph "transaction/mergetransaction"
+
+exec (::a,::b,::c,::d)=init
+show num nodes
+show num edges
+exec matchinit
+exec matchmerge
+exec < merge(::a,::b,::c,::d) && false > 
+show num nodes
+show num edges
+exec matchinit
+exec matchmerge
+
+clear graph
+
+exec (::a,::b,::c,::d)=init
+show num nodes
+show num edges
+exec matchinit
+exec matchmerge
+exec < merge(::a,::b,::c,::d) && true > 
+show num nodes
+show num edges
+exec matchinit
+exec matchmerge
+
+quit

engine-net-2/tests/transaction/mergetransaction.grs.data

+1
+1
+4
+4
+1
+1
+0
+0
+1
+0
+4
+4
+1
+1
+0
+0
+1
+1
+4
+4
+1
+1
+0
+0
+1
+1
+1
+4
+0
+0
+1
+1