Bläddra i källkod

added evolution code for attributes

Lucas Heer 7 år sedan
förälder
incheckning
6a9b7bfb80
7 ändrade filer med 215 tillägg och 48 borttagningar
  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")
     # 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.QtCore import QStateMachine, QState, Qt
 from PyQt5.Qt import QApplication
@@ -10,6 +11,7 @@ from sketchUI.graphics_edge_item import GraphicsEdgeItem
 from wrappers.modelverse import element_list_nice
 import commons
 from evolution.node_ops import NodeDelete
+from evolution.attribute_ops import AttributeDelete
 
 
 class EXMMainWindow(QMainWindow, Ui_MainWindow):
@@ -263,8 +265,8 @@ class EXMMainWindow(QMainWindow, Ui_MainWindow):
 
     def _on_attribute_edited(self, item):
         # 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.
         """
         row = self.tableWidget.row(item)
@@ -273,8 +275,19 @@ class EXMMainWindow(QMainWindow, Ui_MainWindow):
         node = self._scene.selectedItems()[0]
 
         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))
-            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)
         else:
             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"):
         """
-        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]
         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.blockSignals(False)
 
-        # add to modelverse
-        mvops.add_attribute(self._cur_model, selected_node.node_id, key, val)
-
     def _on_delete_model_clicked(self, event):
         # delete the open example model by iteratively deleting all nodes
         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 import mvops
 from evolution.node_ops import NodeAdd, NodeDelete, NodeRetype
+from evolution.attribute_ops import AttributeAdd
 import commons
 
 
@@ -358,58 +359,72 @@ class SketchScene(QGraphicsScene):
         self._parent.plainTextEdit.appendPlainText("OK")
 
     def _handle_keypress_delete(self, selected):
-        del_hander = NodeDelete()
-
         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")
             edge = selected[0]
             mvops.delete_node(self._cur_model, edge.edge_id)
             self.removeItem(edge)
             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():
                     if not isinstance(edge, GraphicsEdgeItem):
                         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(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:
                     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()
 
     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))
                 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):
         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
 
         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
         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)
 
-Date:   Fri May  4 09:34:46 2018
+Date:   Sun May  6 11:42:36 2018
 
 Model author: Yentl Van Tendeloo
 Model name:   MvK Server