瀏覽代碼

next round of evolution fixes for edges: added functions to check and repair a possibly broken conformance relationship

Lucas Heer 7 年之前
父節點
當前提交
40cb2d4afd
共有 2 個文件被更改,包括 55 次插入47 次删除
  1. 50 44
      evolution/edge_ops.py
  2. 5 3
      sketchUI/exm_scene.py

+ 50 - 44
evolution/edge_ops.py

@@ -11,7 +11,7 @@ class EdgeAdd(object):
         self._from_type = ""
         self._to_type = ""
 
-    def execute(self, model, from_node, to_node, local, check_if_last=False):
+    def execute(self, model, from_node, to_node, local):
         self._from_node = from_node
         self._to_node = to_node
 
@@ -23,75 +23,81 @@ class EdgeAdd(object):
         if local:
             mv.transformation_execute_MANUAL("graph_ops/add_edge", {"gm":model}, {"gm":model},
                                              callback=self._callback)
-            if check_if_last:
-                mandatory_edges = commons.get_mandtory_edges()
-                this_edge = commons.Edge(self._from_type, self._to_type)
-                if this_edge in mandatory_edges:
-                    print("Edge {} became mandatory, adding to instance models ...".format(this_edge))
-                    for im in commons.all_instance_models():
-                        nodes_from = commons.all_nodes_with_type(im, self._from_type)
-                        nodes_to = commons.all_nodes_with_type(im, self._to_type)
-                        for nf in nodes_from:
-                            for nt in nodes_to:
-                                self.execute(im, nf, nt, local=True, check_if_last=False)
-
         else:
             for m in commons.all_models():
                 nodes_from = commons.all_nodes_with_type(m, self._from_type)
                 nodes_to = commons.all_nodes_with_type(m, self._to_type)
                 for nf in nodes_from:
                     for nt in nodes_to:
-                        self.execute(m, nf, nt, local=True, check_if_last=False)
+                        self.execute(m, nf, nt, local=True)
 
     def _callback(self, model):
         mv.instantiate(model, "gm/Edge", ("gm/"+self._from_node, "gm/"+self._to_node))
 
+    def repair(self):
+        """
+        Check if the operation invalidated any instance models by making an edge mandatory.
+        If so, repair it by adding the edge there.
+        """
+        mandatory_edges = commons.get_mandtory_edges()
+        this_edge = commons.Edge(self._from_type, self._to_type)
+        if this_edge in mandatory_edges:
+            print("Edge {} became mandatory, adding to instance models ...".format(this_edge))
+            for im in commons.all_instance_models():
+                nodes_from = commons.all_nodes_with_type(im, self._from_type)
+                nodes_to = commons.all_nodes_with_type(im, self._to_type)
+                for nf in nodes_from:
+                    for nt in nodes_to:
+                        self.execute(im, nf, nt, local=True)
+
 
 class EdgeDel(object):
     def __init__(self):
         self._edge = ""
+        self._from_node = ""
+        self._to_node = ""
+        self._from_type = ""
+        self._to_type = ""
 
-    def execute(self, model, edge, local, check_if_last=False):
+    def execute(self, model, edge, local):
         self._edge = edge
-        from_node = mv.read_association_source(model, edge)[0]
-        to_node = mv.read_association_destination(model, edge)[0]
-        from_type = commons.get_node_type(model, from_node)
-        to_type = commons.get_node_type(model, to_node)
+        self._from_node = mv.read_association_source(model, edge)[0]
+        self._to_node = mv.read_association_destination(model, edge)[0]
+
+        if not self._from_type:
+            self._from_type = commons.get_node_type(model, self._from_node)
+        if not self._to_type:
+            self._to_type = commons.get_node_type(model, self._to_node)
 
         if local:
             mv.transformation_execute_MANUAL("graph_ops/del_edge", {"gm":model}, {"gm":model},
                                              callback=self._callback)
-        if check_if_last:
-            # check if this association was the last one in all example models
-            # if yes, delete it from all instance models as well to preserve their validity
-            remaining_instances = 0
-
-            for m in commons.all_example_models():
-                nodes_from = commons.all_nodes_with_type(m, from_type)
-                nodes_to = commons.all_nodes_with_type(m, to_type)
-                for nf in nodes_from:
-                    for nt in nodes_to:
-                        edges = commons.get_associations_between(m, nf, nt)
-                        remaining_instances += len(edges)
-            if remaining_instances == 0:
-                for m in commons.all_instance_models():
-                    nodes_from = commons.all_nodes_with_type(m, from_type)
-                    nodes_to = commons.all_nodes_with_type(m, to_type)
-                    for nf in nodes_from:
-                        for nt in nodes_to:
-                            edges = commons.get_associations_between(m, nf, nt)
-                            for edge in edges:
-                                self.execute(m, edge, local=True, check_if_last=False)
-
         else:
             for m in commons.all_models():
-                nodes_from = commons.all_nodes_with_type(m, from_type)
-                nodes_to = commons.all_nodes_with_type(m, to_type)
+                nodes_from = commons.all_nodes_with_type(m, self._from_type)
+                nodes_to = commons.all_nodes_with_type(m, self._to_type)
                 for nf in nodes_from:
                     for nt in nodes_to:
                         edges = commons.get_associations_between(m, nf, nt)
                         for edge in edges:
-                            self.execute(m, edge, local=True, check_if_last=False)
+                            self.execute(m, edge, local=True)
 
     def _callback(self, model):
         mv.delete_element(model, "gm/"+self._edge)
+
+    def repair(self):
+        """
+        Check if this operation invalidated any instance models by leaving an edge untyped.
+        If so, delete untyped edges.
+        """
+        if not commons.is_edge_supported(self._from_type, self._to_type):
+            print("Edge between {} and {} not supported anymore, deleting from all instance models ...".format(
+                self._from_type, self._to_type))
+            for im in commons.all_instance_models():
+                nodes_from = commons.all_nodes_with_type(im, self._from_type)
+                nodes_to = commons.all_nodes_with_type(im, self._to_type)
+                for nf in nodes_from:
+                    for nt in nodes_to:
+                        edges = commons.get_associations_between(im, nf, nt)
+                        for edge in edges:
+                            self.execute(im, edge, local=True)

+ 5 - 3
sketchUI/exm_scene.py

@@ -185,7 +185,8 @@ class SketchScene(QGraphicsScene):
                     add_handler.execute(self._cur_model, from_item.node_id, to_item.node_id, local=False)
                 else:
                     add_handler.execute(self._cur_model, from_item.node_id, to_item.node_id, local=True)
-                    self.draw_edge(self._connect_from_item, item)
+
+                add_handler.repair()
 
                 # reload model because only then the ids of the edges get set anew
                 self._parent._load_model()
@@ -407,7 +408,7 @@ class SketchScene(QGraphicsScene):
             del_handler = EdgeDel()
             QApplication.setOverrideCursor(Qt.WaitCursor)
             if scope == "Global":
-                del_handler.execute(self._cur_model, edge.edge_id, local=False, check_if_last=False)
+                del_handler.execute(self._cur_model, edge.edge_id, local=False)
                 # delete all edges with same typing in view
                 for item in self.items():
                     if not isinstance(item, GraphicsEdgeItem):
@@ -415,10 +416,11 @@ class SketchScene(QGraphicsScene):
                     if item.from_item.get_type() in [edge_from_type, edge_to_type] and item.to_item.get_type() in [edge_from_type, edge_to_type]:
                         self.removeItem(item)
             else:
-                del_handler.execute(self._cur_model, edge.edge_id, local=True, check_if_last=True)
+                del_handler.execute(self._cur_model, edge.edge_id, local=True)
                 # delete from view
                 self.removeItem(edge)
 
+            del_handler.repair()
             QApplication.restoreOverrideCursor()
 
         elif len(selected) == 1 and isinstance(selected[0], GraphicsNodeItem):