Parcourir la source

some work on concrete syntax rendering: introduced node item for graphicsview

Lucas Heer il y a 7 ans
Parent
commit
fffab54bc7

+ 0 - 6
evolution/node_ops.py

@@ -7,7 +7,6 @@ from commons import *
 class NodeAdd(object):
     def __init__(self):
         self._node_type = ""
-        self._node_id = None
 
     def execute(self, model, node_type, local):
         """
@@ -23,14 +22,9 @@ class NodeAdd(object):
             for m in all_models():
                 self.execute(m, node_type, local=True)
 
-    def get_node_id(self):
-        # attention: in case of global execution, this method returns only the last added node in the last model
-        return self._node_id
-
     def _callback(self, model):
         node_id = mv.instantiate(model, "gm/Node")
         mv.attr_assign(model, node_id, "typeID", self._node_type)
-        self._node_id = node_id
 
 
 class NodeDelete(object):

+ 3 - 3
main.py

@@ -60,8 +60,8 @@ if __name__ == "__main__":
     # load modelverse with necessary models?
     if args.u:
         upload_graph_MM()
-        upload_example_models()
-        upload_instance_model()
+        #upload_example_models()
+        #upload_instance_model()
         upload_ops.upload_evolution_ops()
 
     # determine modeling mode
@@ -78,7 +78,7 @@ if __name__ == "__main__":
     if args.m:
         model = args.m
     else:
-        # no model to open, create an emtpy one
+        # no model to open, create an empty one
         if mode == "IM":
             model = new_instance_model()
         else:

+ 1 - 2
sketchUI/exm_mainwindow.py

@@ -214,8 +214,7 @@ class EXMMainWindow(QMainWindow, Ui_MainWindow):
                 self._add_edge_to_scene(src, target)
 
     def _add_node_to_scene(self, node_id, node_type, x=0, y=0):
-        item = GraphicsNodeItem(node_id)
-        item.setText(node_type)
+        item = GraphicsNodeItem(node_id, node_type)
         item.setPos(x, y)
         item.setFlag(QGraphicsItem.ItemIsMovable, True)
         item.setFlag(QGraphicsItem.ItemIsSelectable, True)

+ 47 - 37
sketchUI/exm_scene.py

@@ -8,6 +8,7 @@ from sketchUI import mvops
 from evolution.node_ops import NodeAdd, NodeDelete, NodeRetype
 from commons import all_nodes_with_type
 
+
 class Mode(Enum):
     SELECT = 0
     CONNECT = 1
@@ -22,7 +23,7 @@ class SketchScene(QGraphicsScene):
         QGraphicsScene.__init__(self)
         self._cur_drawing = False
         self._mode = None  # set from mainwindow on start
-        self._from_item = None  # mouse pressed on this item if in connect mode
+        self._connect_from_item = None  # mouse pressed on this item if in connect mode
         self._cur_model = model
 
         self._orig_point = QPointF()
@@ -40,6 +41,8 @@ class SketchScene(QGraphicsScene):
         return True
 
     def draw_edge(self, from_item, to_item, is_new):
+        # type: (GraphicsNodeItem, GraphicsNodeItem, bool) -> None
+        # draw an edge between two items. If is_new, also add it to the model
         line = GraphicsEdgeItem(from_item, to_item)
         line.setFlag(QGraphicsItem.ItemIsMovable, False)
         line.setFlag(QGraphicsItem.ItemIsSelectable, False)
@@ -56,9 +59,10 @@ class SketchScene(QGraphicsScene):
             self._cur_drawing = True
         elif event.button() == Qt.LeftButton and self._mode == Mode.CONNECT:
             item = self.itemAt(event.scenePos(), QTransform())
-            if not item:
+            if not item or not isinstance(item, GraphicsNodeItem):
                 return
-            self._from_item = item
+            else:
+                self._connect_from_item = item
         else:
             pass
 
@@ -135,9 +139,9 @@ class SketchScene(QGraphicsScene):
 
             elif self._mode == Mode.CONNECT:
                 item = self.itemAt(event.scenePos(), QTransform())
-                if not item:
+                if not item or not isinstance(item, GraphicsNodeItem):
                     return
-                self.draw_edge(self._from_item, item, is_new=True)
+                self.draw_edge(self._connect_from_item, item, is_new=True)
 
             else:
                 pass
@@ -179,10 +183,12 @@ class SketchScene(QGraphicsScene):
 
         else:
             QGraphicsScene.keyPressEvent(self, event)
+        self.clearSelection()
 
     def _handle_keypress_type_on_node(self, item):
-        # type a node = retype it
-        node_type, ok = QInputDialog.getText(self._parent, "Retype node", "New type", text=item.text())
+        # type: (GraphicsNodeItem) -> None
+        # type an already typed node = retype it
+        node_type, ok = QInputDialog.getText(self._parent, "Retype node", "New type", text=item.get_type())
         if not ok:
             # user canceled
             return
@@ -207,14 +213,15 @@ class SketchScene(QGraphicsScene):
         for node_item in self.items():
             if not isinstance(node_item, GraphicsNodeItem):
                 continue
-            if item.text() == node_item.text():
-                node_item.setText(node_type)
+            if item.get_type() == node_item.get_type():
+                node_item.set_type(node_type)
 
         # update list widget
         self._parent.populate_types()
 
     def _handle_keypress_type_on_group(self, group):
-        # type the selected group
+        # type: (QGraphicsItemGroup) -> None
+        # type the selected group = make a real node out of it and store it in the actual model
         # get the type from the user
         node_type, ok = QInputDialog.getText(self._parent, "Type node", "Enter type")
         if not ok:
@@ -235,15 +242,13 @@ class SketchScene(QGraphicsScene):
         add_handler = NodeAdd()
         if scope == "Global":
             add_handler.execute(self._cur_model, node_type, local=False)
-            # Hack: Get node id of newly added node in current model
-            nodeid = all_nodes_with_type(self._cur_model, node_type)[0]
         else:
             add_handler.execute(self._cur_model, node_type, local=True)
-            nodeid = add_handler.get_node_id()
+        # Get node id of newly added node in current model
+        nodeid = all_nodes_with_type(self._cur_model, node_type)[0]
 
         # update view
-        nodeitem = GraphicsNodeItem(nodeid)
-        nodeitem.setText(node_type)
+        nodeitem = GraphicsNodeItem(nodeid, node_type)
         nodeitem.setPos(group.x(), group.y())
         nodeitem.setFlag(QGraphicsItem.ItemIsSelectable, True)
         nodeitem.setFlag(QGraphicsItem.ItemIsMovable, True)
@@ -254,27 +259,32 @@ class SketchScene(QGraphicsScene):
     def _handle_keypress_delete(self, selected):
         del_hander = NodeDelete()
         for item in selected:
-            # only delete nodes, edges are taken care of
-            if not isinstance(item, GraphicsNodeItem):
-                continue
-            # when deleting a node, local or global?
-            scope, ok = QInputDialog.getItem(self._parent, "Select scope", "Scope", ["Local", "Global"])
-            if not ok:
-                return
-            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)
+            # only delete nodes, edges are taken care of later
+            if isinstance(item, GraphicsNodeItem):
+                # when deleting a node, local or global?
+                scope, ok = QInputDialog.getItem(self._parent, "Select scope", "Scope", ["Local", "Global"])
+                if not ok:
+                    return
+                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)
+                else:
+                    # just local, delete from this model only
+                    del_hander.execute(self._cur_model, item.node_id, local=True, check_if_last=True)
+
+                # in view, delete edges that were connected to this node as well
+                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:
+                        self.removeItem(edge)
+
+                self.removeItem(item)
+                # repopulate available types in view since they might have changed
             else:
-                # just local, delete from this model only
-                del_hander.execute(self._cur_model, item.node_id, local=True, check_if_last=True)
-
-            # in view, delete edges that were connected to this node as well
-            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:
-                    self.removeItem(edge)
-
-            self.removeItem(item)
-            # repopulate available types in view since they might have changed
+                for item in selected:
+                    self.removeItem(item)
+
+        # if any node was deleted, repopulate list if available items
+        if any(isinstance(item, GraphicsNodeItem) for item in selected):
             self._parent.populate_types()

+ 29 - 4
sketchUI/graphics_node_item.py

@@ -2,9 +2,34 @@
 QGraphics representation class for a node
 """
 
-from PyQt5.QtWidgets import QGraphicsSimpleTextItem
+from PyQt5.QtWidgets import QGraphicsItem, QStyleOptionGraphicsItem, QWidget
+from PyQt5.Qt import QRectF, QPainter, QFont, Qt
 
-class GraphicsNodeItem(QGraphicsSimpleTextItem):
-    def __init__(self, node_id):
-        QGraphicsSimpleTextItem.__init__(self)
+
+class GraphicsNodeItem(QGraphicsItem):
+    def __init__(self, node_id, node_type=""):
+        QGraphicsItem.__init__(self)
         self.node_id = node_id
+        self._type = node_type
+        self._font = QFont()
+        self._font.setPixelSize(12)
+
+    def set_type(self, node_type):
+        self._type = node_type
+        self.update(self.boundingRect())
+
+    def get_type(self):
+        return self._type
+
+    def boundingRect(self):
+        bbox = QRectF(0, 0, 120, 120)
+        return bbox
+
+    def paint(self, painter, option, widget=None):
+        # type: (QPainter, QStyleOptionGraphicsItem, QWidget) -> None
+        painter.setFont(self._font)
+        painter.drawRect(self.boundingRect())
+
+        text_box = QRectF(0, 100, 120, 20)
+        painter.drawRect(text_box)
+        painter.drawText(text_box, Qt.AlignCenter | Qt.TextDontClip, self._type)

+ 2 - 2
sketchUI/im_mainwindow.py

@@ -88,6 +88,7 @@ class IMMainWindow(QMainWindow, Ui_MainWindow):
     def _state_connect_entered(self):
         self._scene.set_mode(Mode.CONNECT)
         self._make_items_movable(False)
+        self._enable_box_select(False)
         self._enable_list_widget(False)
 
     def _state_select_entered(self):
@@ -120,8 +121,7 @@ class IMMainWindow(QMainWindow, Ui_MainWindow):
             self.graphicsView.setDragMode(QGraphicsView.NoDrag)
 
     def _add_node_to_scene(self, node_id, node_type, x=0, y=0):
-        item = GraphicsNodeItem(node_id)
-        item.setText(node_type)
+        item = GraphicsNodeItem(node_id, node_type)
         item.setPos(x, y)
         item.setFlag(QGraphicsItem.ItemIsMovable, True)
         item.setFlag(QGraphicsItem.ItemIsSelectable, True)

+ 10 - 5
sketchUI/im_scene.py

@@ -2,6 +2,7 @@ from enum import Enum
 from PyQt5.QtWidgets import QGraphicsScene, QGraphicsItem
 from PyQt5.Qt import Qt, QTransform
 from sketchUI.graphics_edge_item import GraphicsEdgeItem
+from sketchUI.graphics_node_item import GraphicsNodeItem
 from sketchUI import mvops
 
 
@@ -14,7 +15,7 @@ class CustomScene(QGraphicsScene):
     def __init__(self, model):
         QGraphicsScene.__init__(self)
         self._mode = None  # set by mainwindow at start
-        self._from_item = None  # store the item to draw the connecting line from
+        self.connect_from_item = None  # store the item to draw the connecting line from
         self._cur_model = model  # the mv model we operate on
 
     def set_mode(self, mode):
@@ -25,7 +26,7 @@ class CustomScene(QGraphicsScene):
             item = self.itemAt(event.scenePos(), QTransform())
             if not item:
                 return
-            self._from_item = item
+            self.connect_from_item = item
 
         QGraphicsScene.mousePressEvent(self, event)
 
@@ -34,7 +35,10 @@ class CustomScene(QGraphicsScene):
             item = self.itemAt(event.scenePos(), QTransform())
             if not item:
                 return
-            self.draw_edge(self._from_item, item, is_new=True)
+            if item == self.connect_from_item:
+                print("Not connecting same elements")
+                return
+            self.draw_edge(self.connect_from_item, item, is_new=True)
 
         if event.button() == Qt.LeftButton and self._mode == Mode.SELECT:
             item = self.itemAt(event.scenePos(), QTransform())
@@ -50,8 +54,9 @@ class CustomScene(QGraphicsScene):
         QGraphicsScene.mouseReleaseEvent(self, event)
 
     def draw_edge(self, from_item, to_item, is_new):
-        from_type = from_item.text()
-        to_type = to_item.text()
+        # type: (GraphicsNodeItem, GraphicsNodeItem, bool) -> None
+        from_type = from_item.get_type()
+        to_type = to_item.get_type()
         if is_new:
             if not mvops.is_edge_supported(from_type, to_type):
                 print("edge not supported between {} and {}".format(from_type, to_type))

+ 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 Apr 20 14:37:38 2018
+Date:   Sat Apr 21 14:23:19 2018
 
 Model author: Yentl Van Tendeloo
 Model name:   MvK Server