|
@@ -1,12 +1,12 @@
|
|
|
from enum import Enum
|
|
|
from PyQt5.QtWidgets import QGraphicsScene, QGraphicsItem, QGraphicsLineItem, QGraphicsRectItem, \
|
|
|
- QGraphicsEllipseItem, QInputDialog
|
|
|
+ QGraphicsEllipseItem, QInputDialog, QGraphicsItemGroup
|
|
|
from PyQt5.Qt import Qt, QPointF, QPen, QTransform
|
|
|
-from PyQt5.QtCore import pyqtSignal
|
|
|
from sketchUI.graphics_edge_item import GraphicsEdgeItem
|
|
|
from sketchUI.graphics_node_item import GraphicsNodeItem
|
|
|
from sketchUI import mvops
|
|
|
-
|
|
|
+from evolution.node_ops import NodeAdd, NodeDelete, NodeRetype
|
|
|
+from commons import all_nodes_with_type
|
|
|
|
|
|
class Mode(Enum):
|
|
|
SELECT = 0
|
|
@@ -149,8 +149,7 @@ class SketchScene(QGraphicsScene):
|
|
|
return
|
|
|
# "del" deletes all selected items
|
|
|
if event.key() == Qt.Key_Delete:
|
|
|
- for item in self.selectedItems():
|
|
|
- self.removeItem(item)
|
|
|
+ self._handle_keypress_delete(self.selectedItems())
|
|
|
|
|
|
# "G" groups selected items
|
|
|
elif event.key() == Qt.Key_G:
|
|
@@ -164,30 +163,118 @@ class SketchScene(QGraphicsScene):
|
|
|
group.setFlag(QGraphicsItem.ItemIsSelectable, True)
|
|
|
group.setFlag(QGraphicsItem.ItemIsMovable, True)
|
|
|
|
|
|
+ # "T" lets user type selected element
|
|
|
elif event.key() == Qt.Key_T:
|
|
|
+ # exactly one element that is a group must be selected
|
|
|
selected = self.selectedItems()
|
|
|
if len(selected) != 1:
|
|
|
return
|
|
|
item = selected[0]
|
|
|
- # "T" lets the user type the selected item
|
|
|
- text, ok = QInputDialog.getText(self._parent, "Text input", "Enter type")
|
|
|
- if ok and text:
|
|
|
- print("Typing item {} to type {}".format(item, text))
|
|
|
- if text in mvops.get_available_types():
|
|
|
- print("Already such a type: {}".format(text))
|
|
|
- return
|
|
|
- self._type_item(item, text)
|
|
|
+ if isinstance(item, QGraphicsItemGroup):
|
|
|
+ self._handle_keypress_type_on_group(item)
|
|
|
+ elif isinstance(item, GraphicsNodeItem):
|
|
|
+ self._handle_keypress_type_on_node(item)
|
|
|
+ else:
|
|
|
+ print("Cannot type element {}".format(item))
|
|
|
+
|
|
|
else:
|
|
|
QGraphicsScene.keyPressEvent(self, event)
|
|
|
|
|
|
- def _type_item(self, item, typ):
|
|
|
- # typing means elevating it to a real node
|
|
|
- nid = mvops.add_node(self._cur_model, typ)
|
|
|
- nodeitem = GraphicsNodeItem(nid)
|
|
|
- nodeitem.setText(typ)
|
|
|
- nodeitem.setPos(item.x(), item.y())
|
|
|
+ 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())
|
|
|
+ if not ok:
|
|
|
+ # user canceled
|
|
|
+ return
|
|
|
+ if node_type:
|
|
|
+ print("Reyping item {} to type {}".format(item, node_type))
|
|
|
+ if node_type in mvops.get_available_types():
|
|
|
+ print("Error: Already such a type: {}".format(node_type))
|
|
|
+ return
|
|
|
+
|
|
|
+ # local or global retype?
|
|
|
+ scope, ok = QInputDialog.getItem(self._parent, "Select scope", "Scope", ["Local", "Global"])
|
|
|
+ if not ok:
|
|
|
+ return
|
|
|
+
|
|
|
+ retype_handler = NodeRetype()
|
|
|
+ if scope == "Global":
|
|
|
+ retype_handler.execute(self._cur_model, item.node_id, node_type, local=False)
|
|
|
+ else:
|
|
|
+ retype_handler.execute(self._cur_model, item.node_id, node_type, local=True)
|
|
|
+
|
|
|
+ # rename on screen
|
|
|
+ for node_item in self.items():
|
|
|
+ if not isinstance(node_item, GraphicsNodeItem):
|
|
|
+ continue
|
|
|
+ if item.text() == node_item.text():
|
|
|
+ node_item.setText(node_type)
|
|
|
+
|
|
|
+ # update list widget
|
|
|
+ self._parent.populate_types()
|
|
|
+
|
|
|
+ def _handle_keypress_type_on_group(self, group):
|
|
|
+ # type the selected group
|
|
|
+ # get the type from the user
|
|
|
+ node_type, ok = QInputDialog.getText(self._parent, "Type node", "Enter type")
|
|
|
+ if not ok:
|
|
|
+ # user canceled
|
|
|
+ return
|
|
|
+ if node_type:
|
|
|
+ print("Typing item {} to type {}".format(group, node_type))
|
|
|
+ if node_type in mvops.get_available_types():
|
|
|
+ print("Error: Already such a type: {}".format(node_type))
|
|
|
+ return
|
|
|
+
|
|
|
+ # perform add local or global?
|
|
|
+ scope, ok = QInputDialog.getItem(self._parent, "Select scope", "Scope", ["Local", "Global"])
|
|
|
+ if not ok:
|
|
|
+ return
|
|
|
+
|
|
|
+ # add the node to the model
|
|
|
+ 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()
|
|
|
+
|
|
|
+ # update view
|
|
|
+ nodeitem = GraphicsNodeItem(nodeid)
|
|
|
+ nodeitem.setText(node_type)
|
|
|
+ nodeitem.setPos(group.x(), group.y())
|
|
|
nodeitem.setFlag(QGraphicsItem.ItemIsSelectable, True)
|
|
|
nodeitem.setFlag(QGraphicsItem.ItemIsMovable, True)
|
|
|
- self.removeItem(item)
|
|
|
+ self.removeItem(group)
|
|
|
self.addItem(nodeitem)
|
|
|
self._parent.populate_types()
|
|
|
+
|
|
|
+ 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)
|
|
|
+ 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
|
|
|
+ self._parent.populate_types()
|