فهرست منبع

added evolution code for attributes

Lucas Heer 7 سال پیش
والد
کامیت
6a9b7bfb80
7فایلهای تغییر یافته به همراه215 افزوده شده و 48 حذف شده
  1. 117 0
      evolution/attribute_ops.py
  2. 7 0
      evolution/upload_ops.py
  3. 18 9
      sketchUI/exm_mainwindow.py
  4. 65 37
      sketchUI/exm_scene.py
  5. 7 0
      tmp.py
  6. 0 1
      verifier.py
  7. 1 1
      wrappers/modelverse_SCCD.py

+ 117 - 0
evolution/attribute_ops.py

@@ -0,0 +1,117 @@
+import sys
+sys.path.append("../wrappers")
+from wrappers import modelverse as mv
+import commons
+
+
+class AttributeAdd(object):
+    def __init__(self):
+        self._key = ""
+        self._value = ""
+        self._node_id = ""
+        self._node_type = ""
+
+    def execute(self, model, node_id, key, value, local):
+        """
+        Add a new attribute (key, value) to node with node_id in model.
+        """
+        self._key = key
+        self._value = value
+        self._node_id = node_id
+
+        if not self._node_type:
+            self._node_type = commons.get_node_type(model, node_id)
+
+        if local:
+            mv.transformation_execute_MANUAL("graph_ops/add_attribute", {"gm":model}, {"gm":model},
+                                             callback=self._callback)
+        else:
+            for m in commons.all_models():
+                nodes = commons.all_nodes_with_type(m, self._node_type)
+                for nid in nodes:
+                    self.execute(m, nid, key, value, local=True)
+
+    def _callback(self, model):
+        attr_id = mv.instantiate(model, "gm/Attribute")
+        mv.attr_assign(model, attr_id, "key", self._key)
+        mv.attr_assign(model, attr_id, "value", self._value)
+        mv.instantiate(model, "gm/NodeAttribute", ("gm/"+self._node_id, attr_id))
+
+
+class AttributeDelete(object):
+    def __init__(self):
+        self._key = ""
+        self._node_id = ""
+        self._node_type = ""
+
+    def execute(self, model, node_id, key, local):
+        """
+        Deletes an attribute identified by its key from node_id in model.
+        """
+        self._key = key
+        self._node_id = node_id
+
+        if not self._node_type:
+            self._node_type = commons.get_node_type(model, node_id)
+
+        if local:
+            mv.transformation_execute_MANUAL("graph_ops/del_attribute", {"gm":model}, {"gm":model},
+                                             callback=self._callback)
+        else:
+            # delete all attributes with key
+            for m in commons.all_models():
+                nodes = commons.all_nodes_with_type(m, self._node_type)
+                for nid in nodes:
+                    self.execute(m, nid, key, local=True)
+
+    def _callback(self, model):
+        outgoings = mv.read_outgoing(model, "gm/"+self._node_id, "gm/NodeAttribute")
+        for edge in outgoings:
+            attr = mv.read_association_destination(model, edge)[0]
+            attr_key = mv.read_attrs(model, attr)["key"]
+            if attr_key == self._key:
+                mv.delete_element(model, attr)
+                break
+
+
+class AttributeChange(object):
+    """
+    Remark: This is currently not needed since the UI does not have the functionality to update an attribute
+    key in-place. Instead, an attribute must be deleted and added with the new key to effectively change the key.
+    Therefore, this is only here for the sake of completeness.
+    """
+    def __init__(self):
+        self._node_id = ""
+        self._old_key = ""
+        self._new_key = ""
+        self._node_type = ""
+
+    def execute(self, model, node_id, old_key, new_key, local):
+        """
+        Update the attribute key old_key of node_id in model to new_key.
+        """
+        self._node_id = node_id
+        self._old_key = old_key
+        self._new_key = new_key
+
+        if not self._node_type:
+            self._node_type = commons.get_node_type(model, node_id)
+
+        if local:
+            mv.transformation_execute_MANUAL("graph_ops/change_attribute", {"gm":model}, {"gm":model},
+                                             callback=self._callback)
+
+        else:
+            for m in commons.all_models():
+                nodes = commons.all_nodes_with_type(m, self._node_type)
+                for nid in nodes:
+                    self.execute(m, nid, old_key, new_key, local=True)
+
+    def _callback(self, model):
+        outgoings = mv.read_outgoing(model, "gm/"+self._node_id, "gm/NodeAttribute")
+        for link in outgoings:
+            attr = mv.read_association_destination(model, link)[0]
+            attr_key = mv.read_attrs(model, attr)["key"]
+            if attr_key == self._old_key:
+                mv.attr_assign(model, attr, "key", self._new_key)
+                break

+ 7 - 0
evolution/upload_ops.py

@@ -21,3 +21,10 @@ def upload_evolution_ops():
     mv.transformation_add_MANUAL({"gm":"formalisms/graphMM"}, {"gm":"formalisms/graphMM"}, "graph_ops/add_edge")
     mv.transformation_add_MANUAL({"gm":"formalisms/graphMM"}, {"gm":"formalisms/graphMM"}, "graph_ops/add_edge")
     # del edge
     # del edge
     mv.transformation_add_MANUAL({"gm":"formalisms/graphMM"}, {"gm":"formalisms/graphMM"}, "graph_ops/del_edge")
     mv.transformation_add_MANUAL({"gm":"formalisms/graphMM"}, {"gm":"formalisms/graphMM"}, "graph_ops/del_edge")
+
+    # add attribute
+    mv.transformation_add_MANUAL({"gm": "formalisms/graphMM"}, {"gm": "formalisms/graphMM"}, "graph_ops/add_attribute")
+    # delete attribute
+    mv.transformation_add_MANUAL({"gm":"formalisms/graphMM"}, {"gm":"formalisms/graphMM"}, "graph_ops/del_attribute")
+    # change attribute key
+    mv.transformation_add_MANUAL({"gm":"formalisms/graphMM"}, {"gm":"formalisms/graphMM"}, "graph_ops/change_attribute")

+ 18 - 9
sketchUI/exm_mainwindow.py

@@ -1,4 +1,5 @@
-from PyQt5.QtWidgets import QMainWindow, QAction, QActionGroup, QGraphicsItem, QGraphicsView, QTableWidgetItem
+from PyQt5.QtWidgets import QMainWindow, QAction, QActionGroup, QGraphicsItem, QGraphicsView,\
+    QTableWidgetItem, QInputDialog
 from PyQt5.QtGui import QIcon
 from PyQt5.QtGui import QIcon
 from PyQt5.QtCore import QStateMachine, QState, Qt
 from PyQt5.QtCore import QStateMachine, QState, Qt
 from PyQt5.Qt import QApplication
 from PyQt5.Qt import QApplication
@@ -10,6 +11,7 @@ from sketchUI.graphics_edge_item import GraphicsEdgeItem
 from wrappers.modelverse import element_list_nice
 from wrappers.modelverse import element_list_nice
 import commons
 import commons
 from evolution.node_ops import NodeDelete
 from evolution.node_ops import NodeDelete
+from evolution.attribute_ops import AttributeDelete
 
 
 
 
 class EXMMainWindow(QMainWindow, Ui_MainWindow):
 class EXMMainWindow(QMainWindow, Ui_MainWindow):
@@ -263,8 +265,8 @@ class EXMMainWindow(QMainWindow, Ui_MainWindow):
 
 
     def _on_attribute_edited(self, item):
     def _on_attribute_edited(self, item):
         # type: (QTableWidgetItem) -> None
         # type: (QTableWidgetItem) -> None
-        """ An attribute was edited, change it in the model but do not check (too expensive so
-        checking is done by verify method on demand).
+        """
+        An attribute value was edited.
         If the new entered value is empty, delete the attribute.
         If the new entered value is empty, delete the attribute.
         """
         """
         row = self.tableWidget.row(item)
         row = self.tableWidget.row(item)
@@ -273,8 +275,19 @@ class EXMMainWindow(QMainWindow, Ui_MainWindow):
         node = self._scene.selectedItems()[0]
         node = self._scene.selectedItems()[0]
 
 
         if not attr_val:
         if not attr_val:
+            # ask if global or local delete
+            scope, ok = QInputDialog.getItem(self._parent, "Select scope", "Scope", ["Local", "Global"])
+            if not ok:
+                return
+            del_handler = AttributeDelete()
             self.plainTextEdit.appendPlainText("Deleting attribute {}".format(attr_key))
             self.plainTextEdit.appendPlainText("Deleting attribute {}".format(attr_key))
-            mvops.delete_attribute_from_node(self._cur_model, node.node_id, attr_key)
+
+            if scope == "Global":
+                del_handler.execute(self._cur_model, node.node_id, attr_key, local=False)
+            else:
+                del_handler.execute(self._cur_model, node.node_id, attr_key, local=True)
+
+            # update view
             self.tableWidget.removeRow(row)
             self.tableWidget.removeRow(row)
         else:
         else:
             self.plainTextEdit.appendPlainText("Updating value of attribute {} to {}".format(attr_key, attr_val))
             self.plainTextEdit.appendPlainText("Updating value of attribute {} to {}".format(attr_key, attr_val))
@@ -282,8 +295,7 @@ class EXMMainWindow(QMainWindow, Ui_MainWindow):
 
 
     def add_new_attribute(self, key, val="unknown"):
     def add_new_attribute(self, key, val="unknown"):
         """
         """
-        Adds a new attribute to the view with key "key" and optional val. Also adds this attribute to the modelverse
-        model.
+        Adds a new attribute to the view with key "key" and optional val.
         """
         """
         selected_node = self._scene.selectedItems()[0]
         selected_node = self._scene.selectedItems()[0]
         self.plainTextEdit.appendPlainText("Adding new attribute with key {} to node {}".format(key, selected_node.get_type()))
         self.plainTextEdit.appendPlainText("Adding new attribute with key {} to node {}".format(key, selected_node.get_type()))
@@ -297,9 +309,6 @@ class EXMMainWindow(QMainWindow, Ui_MainWindow):
         self.tableWidget.setItem(cur_row_cnt, 1, table_item_val)
         self.tableWidget.setItem(cur_row_cnt, 1, table_item_val)
         self.tableWidget.blockSignals(False)
         self.tableWidget.blockSignals(False)
 
 
-        # add to modelverse
-        mvops.add_attribute(self._cur_model, selected_node.node_id, key, val)
-
     def _on_delete_model_clicked(self, event):
     def _on_delete_model_clicked(self, event):
         # delete the open example model by iteratively deleting all nodes
         # delete the open example model by iteratively deleting all nodes
         self.plainTextEdit.appendPlainText("Deleting model ...")
         self.plainTextEdit.appendPlainText("Deleting model ...")

+ 65 - 37
sketchUI/exm_scene.py

@@ -8,6 +8,7 @@ from sketchUI.graphics_sketch_group import SketchGroup
 from sketchUI.graphics_sketch_line import SketchedLineItem
 from sketchUI.graphics_sketch_line import SketchedLineItem
 from sketchUI import mvops
 from sketchUI import mvops
 from evolution.node_ops import NodeAdd, NodeDelete, NodeRetype
 from evolution.node_ops import NodeAdd, NodeDelete, NodeRetype
+from evolution.attribute_ops import AttributeAdd
 import commons
 import commons
 
 
 
 
@@ -358,58 +359,72 @@ class SketchScene(QGraphicsScene):
         self._parent.plainTextEdit.appendPlainText("OK")
         self._parent.plainTextEdit.appendPlainText("OK")
 
 
     def _handle_keypress_delete(self, selected):
     def _handle_keypress_delete(self, selected):
-        del_hander = NodeDelete()
-
         if len(selected) == 1 and isinstance(selected[0], GraphicsEdgeItem):
         if len(selected) == 1 and isinstance(selected[0], GraphicsEdgeItem):
+            # an edge is to be deleted
+            # TODO: use evolution code
             self._parent.plainTextEdit.appendPlainText("Deleting edge")
             self._parent.plainTextEdit.appendPlainText("Deleting edge")
             edge = selected[0]
             edge = selected[0]
             mvops.delete_node(self._cur_model, edge.edge_id)
             mvops.delete_node(self._cur_model, edge.edge_id)
             self.removeItem(edge)
             self.removeItem(edge)
             return
             return
 
 
-        for item in selected:
-            # only delete nodes, edges are taken care of later
-            if isinstance(item, GraphicsNodeItem):
-                self._parent.plainTextEdit.appendPlainText("Deleting node of type {}".format(item.get_type()))
-                # when deleting a node, local or global?
-                scope, ok = QInputDialog.getItem(self._parent, "Select scope", "Scope", ["Local", "Global"])
-                if not ok:
-                    return
-                QApplication.setOverrideCursor(Qt.WaitCursor)
-                if scope == "Global":
-                    # global language evolution, so delete node with same type everywhere
-                    del_hander.execute(self._cur_model, item.node_id, local=False, check_if_last=False)
-                    # also delete its associated CS model
-                    mvops.del_concrete_syntax_model(item.get_type())
-                else:
-                    # just local, delete from this model only
-                    del_hander.execute(self._cur_model, item.node_id, local=True, check_if_last=True)
-                    if del_hander.was_last():
-                        # it was the last node, so delete its CS model as well
-                        mvops.del_concrete_syntax_model(item.get_type())
-
-                # in view, delete edges that were connected to this node as well
-                # modelverse does this on its own so do not delete edges explicitly here
+        elif len(selected) == 1 and isinstance(selected[0], GraphicsNodeItem):
+            del_hander = NodeDelete()
+            node = selected[0]
+            # a node is to be deleted
+            self._parent.plainTextEdit.appendPlainText("Deleting node of type {}".format(node.get_type()))
+            # when deleting a node, local or global?
+            scope, ok = QInputDialog.getItem(self._parent, "Select scope", "Scope", ["Local", "Global"])
+            if not ok:
+                return
+            QApplication.setOverrideCursor(Qt.WaitCursor)
+            if scope == "Global":
+                # global language evolution, so delete node with same type everywhere
+                del_hander.execute(self._cur_model, node.node_id, local=False, check_if_last=False)
+                # also delete its associated CS model
+                mvops.del_concrete_syntax_model(node.get_type())
+
+                # delete all nodes of type from view
+                for item in self.items():
+                    if not isinstance(item, GraphicsNodeItem):
+                        continue
+                    if item.get_type() == node.get_type():
+                        self.removeItem(item)
+
+            else:
+                # just local, delete from this model only
+                del_hander.execute(self._cur_model, node.node_id, local=True, check_if_last=True)
+                if del_hander.was_last():
+                    # it was the last node in the language, so delete its CS model as well
+                    mvops.del_concrete_syntax_model(node.get_type())
+                # delete this node from view
+                self.removeItem(node)
+
+            # in view, delete edges that were connected to this node as well
+            # modelverse does this on its own so do not delete edges explicitly here
+            if scope == "Local":
                 for edge in self.items():
                 for edge in self.items():
                     if not isinstance(edge, GraphicsEdgeItem):
                     if not isinstance(edge, GraphicsEdgeItem):
                         continue
                         continue
-                    if edge.from_item.node_id == item.node_id or edge.to_item.node_id == item.node_id:
+                    if edge.from_item.node_id == node.node_id or edge.to_item.node_id == node.node_id:
+                        self.removeItem(edge)
+            else:
+                # have to remove all edges connected to this type in model
+                for edge in self.items():
+                    if not isinstance(edge, GraphicsEdgeItem):
+                        continue
+                    if edge.from_item.get_type() == node.get_type() or edge.to_item.get_type() == node.get_type():
                         self.removeItem(edge)
                         self.removeItem(edge)
 
 
-                self.removeItem(item)
-
-            elif isinstance(item, GraphicsEdgeItem):
-                continue
+            # repopulate available types just in case
+            self._parent.populate_types()
 
 
-            else:
-                # no NodeItem -> untyped sketch, simply remove
+        else:
+            if not any(isinstance(x, GraphicsNodeItem) for x in selected) and not any(isinstance(x, GraphicsEdgeItem) for x in selected):
+            # neither NodeItem nor EdgeItem in selected -> untyped sketch item, simply remove
                 for obj in selected:
                 for obj in selected:
                     self.removeItem(obj)
                     self.removeItem(obj)
 
 
-        # if any node was deleted, repopulate list of available items
-        if any(isinstance(item, GraphicsNodeItem) for item in selected):
-            self._parent.populate_types()
-
         QApplication.restoreOverrideCursor()
         QApplication.restoreOverrideCursor()
 
 
     def _handle_keypress_attribute(self, selected):
     def _handle_keypress_attribute(self, selected):
@@ -431,7 +446,20 @@ class SketchScene(QGraphicsScene):
                 self._parent.plainTextEdit.appendPlainText("Error: Already such a key for the node: {}".format(key))
                 self._parent.plainTextEdit.appendPlainText("Error: Already such a key for the node: {}".format(key))
                 return
                 return
 
 
-        self._parent.add_new_attribute(key)
+        # ask of global or local add attribute
+        scope, ok = QInputDialog.getItem(self._parent, "Select scope", "Scope", ["Local", "Global"])
+        if not ok:
+            return
+
+        add_handler = AttributeAdd()
+
+        if scope == "Global":
+            add_handler.execute(self._cur_model, item.node_id, key, "unknown", local=False)
+        else:
+            add_handler.execute(self._cur_model, item.node_id, key, "unknown", local=True)
+
+        # add to view
+        self._parent.add_new_attribute(key, "unknown")
 
 
     def highlight_node(self, node_id, color):
     def highlight_node(self, node_id, color):
         for item in self.items():
         for item in self.items():

+ 7 - 0
tmp.py

@@ -0,0 +1,7 @@
+import wrappers.modelverse as mv;mv.init();mv.login("admin", "admin")
+from evolution.attribute_ops import AttributeChange
+
+change_handler = AttributeChange()
+print("performing rename ...")
+change_handler.execute("models/example/ex1", "n1", "IP", "IP_ADDR", local=True)
+print("done")

+ 0 - 1
verifier.py

@@ -215,7 +215,6 @@ class Verifier(object):
                         found = True
                         found = True
 
 
         mandatory_edges = [edge for edge,mandatory in edge_mandatory.iteritems() if mandatory]
         mandatory_edges = [edge for edge,mandatory in edge_mandatory.iteritems() if mandatory]
-        print(mandatory_edges)
 
 
         # check if instance model contains the types and the edge
         # check if instance model contains the types and the edge
         for edge in mandatory_edges:
         for edge in mandatory_edges:

+ 1 - 1
wrappers/modelverse_SCCD.py

@@ -1,7 +1,7 @@
 """
 """
 Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
 Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
 
 
-Date:   Fri May  4 09:34:46 2018
+Date:   Sun May  6 11:42:36 2018
 
 
 Model author: Yentl Van Tendeloo
 Model author: Yentl Van Tendeloo
 Model name:   MvK Server
 Model name:   MvK Server