Esempio n. 1
0
    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)
Esempio n. 2
0
    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)
Esempio n. 3
0
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
Esempio n. 4
0
    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)
Esempio n. 5
0
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
Esempio n. 6
0
    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)
Esempio n. 7
0
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
Esempio n. 8
0
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
Esempio n. 9
0
    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)
Esempio n. 10
0
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
Esempio n. 11
0
    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)
Esempio n. 12
0
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