class CardinalityRestrictionForm(QtWidgets.QDialog): """ This class implements the form used to input domain/range restriction cardinalities. """ def __init__(self, parent=None): """ Initialize the form dialog. :type parent: QtWidgets.QWidget """ super().__init__(parent) ############################################# # FORM AREA ################################# self.minLabel = QtWidgets.QLabel(self) self.minLabel.setText('Min. cardinality') self.minField = IntegerField(self) self.minField.setFixedWidth(80) self.maxLabel = QtWidgets.QLabel(self) self.maxLabel.setText('Max. cardinality') self.maxField = IntegerField(self) self.maxField.setFixedWidth(80) self.formWidget = QtWidgets.QWidget(self) self.formLayout = QtWidgets.QFormLayout(self.formWidget) self.formLayout.addRow(self.minLabel, self.minField) self.formLayout.addRow(self.maxLabel, self.maxField) ############################################# # CONFIRMATION AREA ################################# self.confirmationBox = QtWidgets.QDialogButtonBox( QtCore.Qt.Horizontal, self) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Ok) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Cancel) self.confirmationBox.setContentsMargins(10, 0, 10, 10) ############################################# # SETUP DIALOG LAYOUT ################################# self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.addWidget(self.formWidget) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setFixedSize(self.sizeHint()) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) self.setWindowTitle('Insert cardinality') connect(self.confirmationBox.accepted, self.accept) connect(self.confirmationBox.rejected, self.reject) ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def accept(self): """ Validate the form and trigger accept() if the form is valid. """ v1 = self.min() v2 = self.max() try: if v1 is not None and v1 < 0 or v2 is not None and v2 < 0: raise ValueError('Please enter only <b>positive</b> integers!') if v1 is not None and v2 is not None and v1 > v2: raise ValueError( 'Min. cardinality <b>{0}</b> must be <= than Max. cardinality <b>{1}</b>' .format(v1, v2)) except ValueError as e: msgbox = QtWidgets.QMessageBox(self) msgbox.setIconPixmap( QtGui.QIcon(':/icons/48/ic_warning_black').pixmap(48)) msgbox.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) msgbox.setWindowTitle('Invalid range specified') msgbox.setText(str(e)) msgbox.setTextFormat(QtCore.Qt.RichText) msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok) msgbox.exec_() else: super().accept() ############################################# # INTERFACE ################################# def max(self): """ Returns the maximum cardinality value. :rtype: int """ try: return int(self.maxField.text()) except ValueError: return None def min(self): """ Returns the minimum cardinality value. :rtype: int """ try: return int(self.minField.text()) except ValueError: return None
class DiagramProperty(PropertyDialog): """ This class implements the diagram properties dialog. """ def __init__(self, diagram, session): """ Initialize the diagram properties dialog. :type diagram: Diagram :type session: Session """ super().__init__(session) self.diagram = diagram ############################################# # GENERAL TAB ################################# self.nodesLabel = QtWidgets.QLabel(self) self.nodesLabel.setText('N° nodes') self.nodesField = IntegerField(self) self.nodesField.setFixedWidth(300) self.nodesField.setReadOnly(True) self.nodesField.setValue(len(self.diagram.nodes())) self.edgesLabel = QtWidgets.QLabel(self) self.edgesLabel.setText('N° edges') self.edgesField = IntegerField(self) self.edgesField.setFixedWidth(300) self.edgesField.setReadOnly(True) self.edgesField.setValue(len(self.diagram.edges())) self.generalWidget = QtWidgets.QWidget() self.generalLayout = QtWidgets.QFormLayout(self.generalWidget) self.generalLayout.addRow(self.nodesLabel, self.nodesField) self.generalLayout.addRow(self.edgesLabel, self.edgesField) ############################################# # GEOMETRY TAB ################################# sceneRect = self.diagram.sceneRect() self.diagramSizeLabel = QtWidgets.QLabel(self) self.diagramSizeLabel.setText('Size') self.diagramSizeField = SpinBox(self) self.diagramSizeField.setRange(Diagram.MinSize, Diagram.MaxSize) self.diagramSizeField.setSingleStep(100) self.diagramSizeField.setValue( max(sceneRect.width(), sceneRect.height())) self.geometryWidget = QtWidgets.QWidget() self.geometryLayout = QtWidgets.QFormLayout(self.geometryWidget) self.geometryLayout.addRow(self.diagramSizeLabel, self.diagramSizeField) ############################################# # CONFIRMATION BOX ################################# self.confirmationBox = QtWidgets.QDialogButtonBox( QtCore.Qt.Horizontal, self) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Ok) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Cancel) self.confirmationBox.setContentsMargins(10, 0, 10, 10) ############################################# # MAIN WIDGET ################################# self.mainWidget = QtWidgets.QTabWidget(self) self.mainWidget.addTab(self.generalWidget, 'General') self.mainWidget.addTab(self.geometryWidget, 'Geometry') self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.addWidget(self.mainWidget) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setWindowTitle('Properties: {0}'.format(self.diagram.name)) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) connect(self.confirmationBox.accepted, self.complete) connect(self.confirmationBox.rejected, self.reject) ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def complete(self): """ Executed when the dialog is accepted. """ commands = [self.diagramSizeChanged()] if any(commands): self.session.undostack.beginMacro('edit {0} properties'.format( self.diagram.name)) for command in commands: if command: self.session.undostack.push(command) self.session.undostack.endMacro() super().accept() ############################################# # AUXILIARY METHODS ################################# def diagramSizeChanged(self): """ Change the size of the diagram. :rtype: QUndoCommand """ sceneRect = self.diagram.sceneRect() size1 = max(sceneRect.width(), sceneRect.height()) size2 = self.diagramSizeField.value() if size1 != size2: items = self.diagram.items() if items: x = set() y = set() for item in items: if item.isEdge() or item.isNode(): b = item.mapRectToScene(item.boundingRect()) x.update({b.left(), b.right()}) y.update({b.top(), b.bottom()}) size2 = max(size2, abs(min(x) * 2), abs(max(x) * 2), abs(min(y) * 2), abs(max(y) * 2)) return CommandDiagramResize( self.diagram, QtCore.QRectF(-size2 / 2, -size2 / 2, size2, size2)) return None
class NodeProperty(PropertyDialog): """ This class implements the 'Node property' dialog. """ def __init__(self, diagram, node, session): """ Initialize the node properties dialog. :type diagram: Diagram :type node: AbstractNode :type session: Session """ super().__init__(session) self.diagram = diagram self.node = node ############################################# # GENERAL TAB ################################# self.idLabel = QtWidgets.QLabel(self) self.idLabel.setText('ID') self.idField = StringField(self) self.idField.setFixedWidth(300) self.idField.setFocusPolicy(QtCore.Qt.NoFocus) self.idField.setReadOnly(True) self.idField.setValue(self.node.id) self.typeLabel = QtWidgets.QLabel(self) self.typeLabel.setText('Type') self.typeField = StringField(self) self.typeField.setFocusPolicy(QtCore.Qt.NoFocus) self.typeField.setFixedWidth(300) self.typeField.setReadOnly(True) self.typeField.setValue(node.shortName.capitalize()) self.identityLabel = QtWidgets.QLabel(self) self.identityLabel.setText('Identity') self.identityField = StringField(self) self.identityField.setFocusPolicy(QtCore.Qt.NoFocus) self.identityField.setFixedWidth(300) self.identityField.setReadOnly(True) self.identityField.setValue(self.node.identityName) self.neighboursLabel = QtWidgets.QLabel(self) self.neighboursLabel.setText('Neighbours') self.neighboursField = IntegerField(self) self.neighboursField.setFocusPolicy(QtCore.Qt.NoFocus) self.neighboursField.setFixedWidth(300) self.neighboursField.setReadOnly(True) self.neighboursField.setValue(len(self.node.adjacentNodes())) self.generalWidget = QtWidgets.QWidget() self.generalLayout = QtWidgets.QFormLayout(self.generalWidget) self.generalLayout.addRow(self.idLabel, self.idField) self.generalLayout.addRow(self.typeLabel, self.typeField) self.generalLayout.addRow(self.identityLabel, self.identityField) self.generalLayout.addRow(self.neighboursLabel, self.neighboursField) ############################################# # GEOMETRY TAB ################################# nodePos = self.node.pos() sceneRect = self.diagram.sceneRect() self.xLabel = QtWidgets.QLabel(self) self.xLabel.setText('X') self.xField = SpinBox(self) self.xField.setFixedWidth(60) self.xField.setRange(sceneRect.left(), sceneRect.right()) self.xField.setValue(int(nodePos.x())) self.yLabel = QtWidgets.QLabel(self) self.yLabel.setText('Y') self.yField = SpinBox(self) self.yField.setFixedWidth(60) self.yField.setRange(sceneRect.top(), sceneRect.bottom()) self.yField.setValue(int(nodePos.y())) self.widthLabel = QtWidgets.QLabel(self) self.widthLabel.setText('Width') self.widthField = SpinBox(self) self.widthField.setFixedWidth(60) self.widthField.setRange(20, sceneRect.width()) self.widthField.setReadOnly(True) self.widthField.setValue(int(self.node.width())) self.heightLabel = QtWidgets.QLabel(self) self.heightLabel.setText('Height') self.heightField = SpinBox(self) self.heightField.setFixedWidth(60) self.heightField.setRange(20, sceneRect.height()) self.heightField.setReadOnly(True) self.heightField.setValue(int(self.node.height())) self.geometryWidget = QtWidgets.QWidget() self.geometryLayout = QtWidgets.QFormLayout(self.geometryWidget) self.geometryLayout.addRow(self.xLabel, self.xField) self.geometryLayout.addRow(self.yLabel, self.yField) self.geometryLayout.addRow(self.widthLabel, self.widthField) self.geometryLayout.addRow(self.heightLabel, self.heightField) ############################################# # CONFIRMATION BOX ################################# self.confirmationBox = QtWidgets.QDialogButtonBox( QtCore.Qt.Horizontal, self) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Ok) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Cancel) self.confirmationBox.setContentsMargins(10, 0, 10, 10) ############################################# # MAIN WIDGET ################################# self.mainWidget = QtWidgets.QTabWidget(self) self.mainWidget.addTab(self.generalWidget, 'General') self.mainWidget.addTab(self.geometryWidget, 'Geometry') self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.addWidget(self.mainWidget) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setWindowTitle('Properties: {0}'.format(self.node)) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) connect(self.confirmationBox.accepted, self.complete) connect(self.confirmationBox.rejected, self.reject) ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def complete(self): """ Executed when the dialog is accepted. """ commands = [self.positionChanged()] if any(commands): self.session.undostack.beginMacro('edit {0} properties'.format( self.node.name)) for command in commands: if command: self.session.undostack.push(command) self.session.undostack.endMacro() super().accept() ############################################# # AUXILIARY METHODS ################################# def positionChanged(self): """ Move the node properly if the position has been changed. :rtype: QUndoCommand """ rect = self.diagram.sceneRect() xPos = clamp(self.xField.value(), rect.left(), rect.right()) yPos = clamp(self.yField.value(), rect.top(), rect.bottom()) pos1 = self.node.pos() pos2 = QtCore.QPointF(xPos, yPos) if pos1 != pos2: initData = self.diagram.setupMove([self.node]) moveData = self.diagram.completeMove(initData, pos2 - pos1) return CommandNodeMove(self.diagram, initData, moveData) return None
class CardinalityRestrictionForm(QtWidgets.QDialog): """ This class implements the form used to input domain/range restriction cardinalities. """ def __init__(self, parent=None): """ Initialize the form dialog. :type parent: QtWidgets.QWidget """ super().__init__(parent) ############################################# # FORM AREA ################################# self.minLabel = QtWidgets.QLabel(self) self.minLabel.setFont(Font('Roboto', 12)) self.minLabel.setText('Min. cardinality') self.minField = IntegerField(self) self.minField.setFont(Font('Roboto', 12)) self.minField.setFixedWidth(80) self.maxLabel = QtWidgets.QLabel(self) self.maxLabel.setFont(Font('Roboto', 12)) self.maxLabel.setText('Max. cardinality') self.maxField = IntegerField(self) self.maxField.setFont(Font('Roboto', 12)) self.maxField.setFixedWidth(80) self.formWidget = QtWidgets.QWidget(self) self.formLayout = QtWidgets.QFormLayout(self.formWidget) self.formLayout.addRow(self.minLabel, self.minField) self.formLayout.addRow(self.maxLabel, self.maxField) ############################################# # CONFIRMATION AREA ################################# self.confirmationBox = QtWidgets.QDialogButtonBox(QtCore.Qt.Horizontal, self) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Ok) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Cancel) self.confirmationBox.setContentsMargins(10, 0, 10, 10) self.confirmationBox.setFont(Font('Roboto', 12)) ############################################# # SETUP DIALOG LAYOUT ################################# self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.addWidget(self.formWidget) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setFixedSize(self.sizeHint()) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) self.setWindowTitle('Insert cardinality') connect(self.confirmationBox.accepted, self.accept) connect(self.confirmationBox.rejected, self.reject) ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def accept(self): """ Validate the form and trigger accept() if the form is valid. """ v1 = self.min() v2 = self.max() try: if v1 is not None and v1 < 0 or v2 is not None and v2 < 0: raise ValueError('Please enter only <b>positive</b> integers!') if v1 is not None and v2 is not None and v1 > v2: raise ValueError('Min. cardinality <b>{0}</b> must be <= than Max. cardinality <b>{1}</b>'.format(v1, v2)) except ValueError as e: msgbox = QtWidgets.QMessageBox(self) msgbox.setIconPixmap(QtGui.QIcon(':/icons/48/ic_warning_black').pixmap(48)) msgbox.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) msgbox.setWindowTitle('Invalid range specified') msgbox.setText(str(e)) msgbox.setTextFormat(QtCore.Qt.RichText) msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok) msgbox.exec_() else: super().accept() ############################################# # INTERFACE ################################# def max(self): """ Returns the maximum cardinality value. :rtype: int """ try: return int(self.maxField.text()) except ValueError: return None def min(self): """ Returns the minimum cardinality value. :rtype: int """ try: return int(self.minField.text()) except ValueError: return None
class DiagramProperty(PropertyDialog): """ This class implements the diagram properties dialog. """ def __init__(self, diagram, session): """ Initialize the diagram properties dialog. :type diagram: Diagram :type session: Session """ super().__init__(session) self.diagram = diagram ############################################# # GENERAL TAB ################################# self.nodesLabel = QtWidgets.QLabel(self) self.nodesLabel.setFont(Font('Roboto', 12)) self.nodesLabel.setText('N° nodes') self.nodesField = IntegerField(self) self.nodesField.setFixedWidth(300) self.nodesField.setFont(Font('Roboto', 12)) self.nodesField.setReadOnly(True) self.nodesField.setValue(len(self.diagram.nodes())) self.edgesLabel = QtWidgets.QLabel(self) self.edgesLabel.setFont(Font('Roboto', 12)) self.edgesLabel.setText('N° edges') self.edgesField = IntegerField(self) self.edgesField.setFixedWidth(300) self.edgesField.setFont(Font('Roboto', 12)) self.edgesField.setReadOnly(True) self.edgesField.setValue(len(self.diagram.edges())) self.generalWidget = QtWidgets.QWidget() self.generalLayout = QtWidgets.QFormLayout(self.generalWidget) self.generalLayout.addRow(self.nodesLabel, self.nodesField) self.generalLayout.addRow(self.edgesLabel, self.edgesField) ############################################# # GEOMETRY TAB ################################# sceneRect = self.diagram.sceneRect() self.diagramSizeLabel = QtWidgets.QLabel(self) self.diagramSizeLabel.setFont(Font('Roboto', 12)) self.diagramSizeLabel.setText('Size') self.diagramSizeField = SpinBox(self) self.diagramSizeField.setFont(Font('Roboto', 12)) self.diagramSizeField.setRange(Diagram.MinSize, Diagram.MaxSize) self.diagramSizeField.setSingleStep(100) self.diagramSizeField.setValue(max(sceneRect.width(), sceneRect.height())) self.geometryWidget = QtWidgets.QWidget() self.geometryLayout = QtWidgets.QFormLayout(self.geometryWidget) self.geometryLayout.addRow(self.diagramSizeLabel, self.diagramSizeField) ############################################# # CONFIRMATION BOX ################################# self.confirmationBox = QtWidgets.QDialogButtonBox(QtCore.Qt.Horizontal, self) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Ok) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Cancel) self.confirmationBox.setContentsMargins(10, 0, 10, 10) self.confirmationBox.setFont(Font('Roboto', 12)) ############################################# # MAIN WIDGET ################################# self.mainWidget = QtWidgets.QTabWidget(self) self.mainWidget.addTab(self.generalWidget,'General') self.mainWidget.addTab(self.geometryWidget, 'Geometry') self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.addWidget(self.mainWidget) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setWindowTitle('Properties: {0}'.format(self.diagram.name)) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) connect(self.confirmationBox.accepted, self.complete) connect(self.confirmationBox.rejected, self.reject) ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def complete(self): """ Executed when the dialog is accepted. """ commands = [self.diagramSizeChanged()] if any(commands): self.session.undostack.beginMacro('edit {0} properties'.format(self.diagram.name)) for command in commands: if command: self.session.undostack.push(command) self.session.undostack.endMacro() super().accept() ############################################# # AUXILIARY METHODS ################################# def diagramSizeChanged(self): """ Change the size of the diagram. :rtype: QUndoCommand """ sceneRect = self.diagram.sceneRect() size1 = max(sceneRect.width(), sceneRect.height()) size2 = self.diagramSizeField.value() if size1 != size2: items = self.diagram.items() if items: x = set() y = set() for item in items: if item.isEdge() or item.isNode(): b = item.mapRectToScene(item.boundingRect()) x.update({b.left(), b.right()}) y.update({b.top(), b.bottom()}) size2 = max(size2, abs(min(x) * 2), abs(max(x) * 2), abs(min(y) * 2), abs(max(y) * 2)) return CommandDiagramResize(self.diagram, QtCore.QRectF(-size2 / 2, -size2 / 2, size2, size2)) return None
class NodeProperty(PropertyDialog): """ This class implements the 'Node property' dialog. """ def __init__(self, diagram, node, session): """ Initialize the node properties dialog. :type diagram: Diagram :type node: AbstractNode :type session: Session """ super().__init__(session) self.diagram = diagram self.node = node ############################################# # GENERAL TAB ################################# self.idLabel = QtWidgets.QLabel(self) self.idLabel.setFont(Font('Roboto', 12)) self.idLabel.setText('ID') self.idField = StringField(self) self.idField.setFont(Font('Roboto', 12)) self.idField.setFixedWidth(300) self.idField.setFocusPolicy(QtCore.Qt.NoFocus) self.idField.setReadOnly(True) self.idField.setValue(self.node.id) self.typeLabel = QtWidgets.QLabel(self) self.typeLabel.setFont(Font('Roboto', 12)) self.typeLabel.setText('Type') self.typeField = StringField(self) self.typeField.setFont(Font('Roboto', 12)) self.typeField.setFocusPolicy(QtCore.Qt.NoFocus) self.typeField.setFixedWidth(300) self.typeField.setReadOnly(True) self.typeField.setValue(node.shortName.capitalize()) self.identityLabel = QtWidgets.QLabel(self) self.identityLabel.setFont(Font('Roboto', 12)) self.identityLabel.setText('Identity') self.identityField = StringField(self) self.identityField.setFont(Font('Roboto', 12)) self.identityField.setFocusPolicy(QtCore.Qt.NoFocus) self.identityField.setFixedWidth(300) self.identityField.setReadOnly(True) self.identityField.setValue(self.node.identityName) self.neighboursLabel = QtWidgets.QLabel(self) self.neighboursLabel.setFont(Font('Roboto', 12)) self.neighboursLabel.setText('Neighbours') self.neighboursField = IntegerField(self) self.neighboursField.setFont(Font('Roboto', 12)) self.neighboursField.setFocusPolicy(QtCore.Qt.NoFocus) self.neighboursField.setFixedWidth(300) self.neighboursField.setReadOnly(True) self.neighboursField.setValue(len(self.node.adjacentNodes())) self.generalWidget = QtWidgets.QWidget() self.generalLayout = QtWidgets.QFormLayout(self.generalWidget) self.generalLayout.addRow(self.idLabel, self.idField) self.generalLayout.addRow(self.typeLabel, self.typeField) self.generalLayout.addRow(self.identityLabel, self.identityField) self.generalLayout.addRow(self.neighboursLabel, self.neighboursField) ############################################# # GEOMETRY TAB ################################# nodePos = self.node.pos() sceneRect = self.diagram.sceneRect() self.xLabel = QtWidgets.QLabel(self) self.xLabel.setFont(Font('Roboto', 12)) self.xLabel.setText('X') self.xField = SpinBox(self) self.xField.setFixedWidth(60) self.xField.setFont(Font('Roboto', 12)) self.xField.setRange(sceneRect.left(), sceneRect.right()) self.xField.setValue(int(nodePos.x())) self.yLabel = QtWidgets.QLabel(self) self.yLabel.setFont(Font('Roboto', 12)) self.yLabel.setText('Y') self.yField = SpinBox(self) self.yField.setFixedWidth(60) self.yField.setFont(Font('Roboto', 12)) self.yField.setRange(sceneRect.top(), sceneRect.bottom()) self.yField.setValue(int(nodePos.y())) self.widthLabel = QtWidgets.QLabel(self) self.widthLabel.setFont(Font('Roboto', 12)) self.widthLabel.setText('Width') self.widthField = SpinBox(self) self.widthField.setFixedWidth(60) self.widthField.setFont(Font('Roboto', 12)) self.widthField.setRange(20, sceneRect.width()) self.widthField.setReadOnly(True) self.widthField.setValue(int(self.node.width())) self.heightLabel = QtWidgets.QLabel(self) self.heightLabel.setFont(Font('Roboto', 12)) self.heightLabel.setText('Height') self.heightField = SpinBox(self) self.heightField.setFixedWidth(60) self.heightField.setFont(Font('Roboto', 12)) self.heightField.setRange(20, sceneRect.height()) self.heightField.setReadOnly(True) self.heightField.setValue(int(self.node.height())) self.geometryWidget = QtWidgets.QWidget() self.geometryLayout = QtWidgets.QFormLayout(self.geometryWidget) self.geometryLayout.addRow(self.xLabel, self.xField) self.geometryLayout.addRow(self.yLabel, self.yField) self.geometryLayout.addRow(self.widthLabel, self.widthField) self.geometryLayout.addRow(self.heightLabel, self.heightField) ############################################# # CONFIRMATION BOX ################################# self.confirmationBox = QtWidgets.QDialogButtonBox(QtCore.Qt.Horizontal, self) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Ok) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Cancel) self.confirmationBox.setContentsMargins(10, 0, 10, 10) self.confirmationBox.setFont(Font('Roboto', 12)) ############################################# # MAIN WIDGET ################################# self.mainWidget = QtWidgets.QTabWidget(self) self.mainWidget.addTab(self.generalWidget, 'General') self.mainWidget.addTab(self.geometryWidget, 'Geometry') self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.addWidget(self.mainWidget) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setWindowTitle('Properties: {0}'.format(self.node)) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) connect(self.confirmationBox.accepted, self.complete) connect(self.confirmationBox.rejected, self.reject) ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def complete(self): """ Executed when the dialog is accepted. """ commands = [self.positionChanged()] if any(commands): self.session.undostack.beginMacro('edit {0} properties'.format(self.node.name)) for command in commands: if command: self.session.undostack.push(command) self.session.undostack.endMacro() super().accept() ############################################# # AUXILIARY METHODS ################################# def positionChanged(self): """ Move the node properly if the position has been changed. :rtype: QUndoCommand """ rect = self.diagram.sceneRect() xPos = clamp(self.xField.value(), rect.left(), rect.right()) yPos = clamp(self.yField.value(), rect.top(), rect.bottom()) pos1 = self.node.pos() pos2 = QtCore.QPointF(xPos, yPos) if pos1 != pos2: node = self.node data = { 'redo': { 'nodes': {node: {'anchors': {k: v + pos2 - pos1 for k, v in node.anchors.items()}, 'pos': pos2}}, 'edges': {}, }, 'undo': { 'nodes': {node: {'anchors': {k: v for k, v in node.anchors.items()}, 'pos': pos1}}, 'edges': {} } } return CommandNodeMove(self.diagram, data) return None