Exemple #1
0
class AttributeNode(OntologyEntityNode):
    """
    This class implements the 'Attribute' node.
    """
    DefaultBrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1,
                            QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                            QtCore.Qt.RoundJoin)
    Identities = {Identity.Attribute, Identity.Individual}
    Type = Item.AttributeIRINode

    def __init__(self, iri=None, width=20, height=20, brush=None, **kwargs):
        """
        Initialize the node.
        :type width: int
        :type height: int
        :type brush: QBrush
        """
        super().__init__(iri=iri, **kwargs)
        brush = brush or AttributeNode.DefaultBrush
        pen = AttributeNode.DefaultPen
        self.fpolygon = Polygon(QtGui.QPainterPath())
        self.background = Polygon(QtCore.QRectF(-14, -14, 28, 28))
        self.selection = Polygon(QtCore.QRectF(-14, -14, 28, 28))
        self.polygon = Polygon(QtCore.QRectF(-10, -10, 20, 20), brush, pen)

    def connectIRIMetaSignals(self):
        connect(self.iri.sgnFunctionalModified, self.onFunctionalModified)

    def disconnectIRIMetaSignals(self):
        disconnect(self.iri.sgnFunctionalModified, self.onFunctionalModified)

    @QtCore.pyqtSlot()
    def onFunctionalModified(self):
        self.updateNode()

    #############################################
    #   INTERFACE
    #################################
    def initialLabelPosition(self):
        return self.center() - QtCore.QPointF(0, 22)

    def occursAsIndividual(self):
        #Class Assertion
        for instEdge in [
                x for x in self.edges if x.type() is Item.MembershipEdge
        ]:
            if instEdge.source is self:
                return True
        #Object[Data] Property Assertion
        for inputEdge in [x for x in self.edges if x.type() is Item.InputEdge]:
            if inputEdge.source is self and inputEdge.target.type(
            ) is Item.PropertyAssertionNode:
                return True
        #SameAs and Different
        for inputEdge in [
                x for x in self.edges
                if (x.type() is Item.SameEdge or x.type() is Item.DifferentEdge
                    )
        ]:
            if inputEdge.source is self or inputEdge.target is self:
                return True
        return False

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QRectF
        """
        return self.selection.geometry()

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        node = diagram.factory.create(
            self.type(), **{
                'id': self.id,
                'brush': self.brush(),
                'height': self.height(),
                'width': self.width(),
                'iri': None,
            })
        node.setPos(self.pos())
        node.iri = self.iri
        node.setTextPos(node.mapFromScene(self.mapToScene(self.textPos())))
        return node

    def definition(self):
        """
        Returns the list of nodes which contribute to the definition of this very node.
        :rtype: set
        """
        f1 = lambda x: x.type() is Item.InputEdge
        f2 = lambda x: x.type(
        ) in {Item.DomainRestrictionNode, Item.RangeRestrictionNode}
        return set(self.outgoingNodes(filter_on_edges=f1, filter_on_nodes=f2))

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        return self.polygon.geometry().height()

    def identity(self):
        """
        Returns the identity of the current node.
        :rtype: Identity
        """
        return Identity.Attribute

    def isFunctional(self):
        """
        Returns True if the predicate represented by this node is functional, else False.
        :rtype: bool
        """
        return self.iri.functional

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawEllipse(self.selection.geometry())
        # SYNTAX VALIDATION
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawEllipse(self.background.geometry())
        # ITEM SHAPE
        painter.setPen(self.polygon.pen())
        painter.setBrush(self.polygon.brush())
        painter.drawEllipse(self.polygon.geometry())
        # FUNCTIONALITY
        painter.setPen(self.fpolygon.pen())
        painter.setBrush(self.fpolygon.brush())
        painter.drawPath(self.fpolygon.geometry())

    def painterPath(self):
        """
        Returns the current shape as QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addEllipse(self.polygon.geometry())
        return path

    def setFunctional(self, functional):
        """
        Set the functional property of the predicate represented by this node.
        :type functional: bool
        """
        self.iri.functional = functional

    def setIdentity(self, identity):
        """
        Set the identity of the current node.
        :type identity: Identity
        """
        pass

    def setText(self, text):
        """
        Set the label text.
        :type text: str
        """
        self.label.setText(text)
        self.label.setAlignment(QtCore.Qt.AlignCenter)

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        self.label.setPos(pos)

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addEllipse(self.polygon.geometry())
        return path

    def special(self):
        """
        Returns the special type of this node.
        :rtype: Special
        """
        # TODO implementa nuova versione passando da metodo IRI.isTopBottomEntity (isOWlThing? etc etc...)
        return Special.valueOf(self.text())

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        return self.label.text()

    def textPos(self):
        """
        Returns the current label position in item coordinates.
        :rtype: QPointF
        """
        return self.label.pos()

    def updateNode(self, functional=None, **kwargs):
        """
        Update the current node.
        :type functional: bool
        """
        if functional is None:
            if self.iri:
                functional = self.isFunctional()
                # TODO CANCELLA
                if functional is None:
                    functional = False
                # TODO END CANCELLA

        # FUNCTIONAL POLYGON (SHAPE)
        path1 = QtGui.QPainterPath()
        path1.addEllipse(self.polygon.geometry())
        path2 = QtGui.QPainterPath()
        path2.addEllipse(QtCore.QRectF(-7, -7, 14, 14))
        self.fpolygon.setGeometry(path1.subtracted(path2))

        # FUNCTIONAL POLYGON (PEN & BRUSH)
        pen = QtGui.QPen(QtCore.Qt.NoPen)
        brush = QtGui.QBrush(QtCore.Qt.NoBrush)
        if functional:
            pen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1,
                             QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                             QtCore.Qt.RoundJoin)
            brush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
        self.fpolygon.setPen(pen)
        self.fpolygon.setBrush(brush)

        # SELECTION + BACKGROUND + CACHE REFRESH
        super().updateNode(**kwargs)

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        self.label.updatePos(*args, **kwargs)

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        return self.polygon.geometry().width()

    def __repr__(self):
        """
        Returns repr(self).
        """
        return '{0}:{1}:{2}'.format(self.__class__.__name__, self.text(),
                                    self.id)
Exemple #2
0
class IndividualNode(OntologyEntityResizableNode):
    """
    This class implements the 'Individual' node.
    """
    IndexLT = 0
    IndexLB = 1
    IndexBL = 2
    IndexBR = 3
    IndexRB = 4
    IndexRT = 5
    IndexTR = 6
    IndexTL = 7
    IndexEE = 8

    DefaultBrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.0,
                            QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                            QtCore.Qt.RoundJoin)
    Identities = {Identity.Individual}
    Type = Item.IndividualIRINode

    def __init__(self, iri=None, width=60, height=60, brush=None, **kwargs):
        """
        Initialize the node.
        :type iri: IRI
        :type width: int
        :type height: int
        :type brush: QBrush
        """
        super().__init__(iri=iri, **kwargs)
        w = max(width, 60)
        h = max(height, 60)
        brush = brush or IndividualNode.DefaultBrush
        pen = IndividualNode.DefaultPen

        createPolygon = lambda x, y: QtGui.QPolygonF([
            QtCore.QPointF(-(x / 2), -((y / (1 + math.sqrt(2))) / 2)),
            QtCore.QPointF(-(x / 2), +((y / (1 + math.sqrt(2))) / 2)),
            QtCore.QPointF(-((x / (1 + math.sqrt(2))) / 2), +(y / 2)),
            QtCore.QPointF(+((x / (1 + math.sqrt(2))) / 2), +(y / 2)),
            QtCore.QPointF(+(x / 2), +((y / (1 + math.sqrt(2))) / 2)),
            QtCore.QPointF(+(x / 2), -((y / (1 + math.sqrt(2))) / 2)),
            QtCore.QPointF(+((x / (1 + math.sqrt(2))) / 2), -(y / 2)),
            QtCore.QPointF(-((x / (1 + math.sqrt(2))) / 2), -(y / 2)),
            QtCore.QPointF(-(x / 2), -((y / (1 + math.sqrt(2))) / 2)),
        ])

        self.background = Polygon(createPolygon(w + 8, h + 8))
        self.selection = Polygon(createPolygon(w + 8, h + 8))
        self.polygon = Polygon(createPolygon(w, h), brush, pen)

        self.updateNode()

    #############################################
    #   INTERFACE
    #################################
    def initialLabelPosition(self):
        return self.center()

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QtCore.QRectF
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.selection.geometry())
        return path.boundingRect()

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        node = diagram.factory.create(
            self.type(), **{
                'id': self.id,
                'brush': self.brush(),
                'height': self.height(),
                'width': self.width(),
                'iri': None,
            })
        node.setPos(self.pos())
        node.iri = self.iri
        node.setTextPos(node.mapFromScene(self.mapToScene(self.textPos())))
        return node

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        polygon = self.polygon.geometry()

        # return polygon[self.IndexTR].y() - polygon[self.IndexBR].y()
        return polygon[self.IndexBR].y() - polygon[self.IndexTR].y()

    def identity(self):
        """
        Returns the identity of the current node.
        :rtype: Identity
        """
        return Identity.Individual

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawPolygon(self.selection.geometry())
        # SYNTAX VALIDATION
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawPolygon(self.background.geometry())
        # ITEM SHAPE
        painter.setPen(self.polygon.pen())
        painter.setBrush(self.polygon.brush())
        painter.drawPolygon(self.polygon.geometry())
        # RESIZE HANDLES
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        for polygon in self.handles:
            painter.setPen(polygon.pen())
            painter.setBrush(polygon.brush())
            painter.drawEllipse(polygon.geometry())

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        return path

    def resize(self, mousePos):
        """
        Handle the interactive resize of the shape.
        :type mousePos: QtCore.QPointF
        """
        snap = self.session.action('toggle_grid').isChecked()
        size = self.diagram.GridSize
        moved = self.label.isMoved()

        background = self.background.geometry()
        selection = self.selection.geometry()
        polygon = self.polygon.geometry()

        R = QtCore.QRectF(self.boundingRect())
        D = QtCore.QPointF(0, 0)

        mbrh = 68
        mbrw = 68

        self.prepareGeometryChange()

        if self.mp_Handle == self.HandleTL:

            fromX = self.mp_Bound.left()
            fromY = self.mp_Bound.top()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, -4, snap)
            toY = snapF(toY, size, -4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            newSideY = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newSideX = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSideY / 2
            newLeftRightTopY = (R.y() + R.height() / 2) - newSideY / 2
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSideX / 2
            newTopBottomRightX = (R.x() + R.width() / 2) + newSideX / 2

            selection[self.IndexLT] = QtCore.QPointF(R.left(),
                                                     newLeftRightTopY)
            selection[self.IndexLB] = QtCore.QPointF(R.left(),
                                                     newLeftRightBottomY)
            selection[self.IndexRT] = QtCore.QPointF(R.right(),
                                                     newLeftRightTopY)
            selection[self.IndexRB] = QtCore.QPointF(R.right(),
                                                     newLeftRightBottomY)
            selection[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                     R.top())
            selection[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                     R.top())
            selection[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                     R.bottom())
            selection[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                     R.bottom())
            selection[self.IndexEE] = QtCore.QPointF(R.left(),
                                                     newLeftRightTopY)

            background[self.IndexLT] = QtCore.QPointF(R.left(),
                                                      newLeftRightTopY)
            background[self.IndexLB] = QtCore.QPointF(R.left(),
                                                      newLeftRightBottomY)
            background[self.IndexRT] = QtCore.QPointF(R.right(),
                                                      newLeftRightTopY)
            background[self.IndexRB] = QtCore.QPointF(R.right(),
                                                      newLeftRightBottomY)
            background[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                      R.top())
            background[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                      R.top())
            background[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                      R.bottom())
            background[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                      R.bottom())
            background[self.IndexEE] = QtCore.QPointF(R.left(),
                                                      newLeftRightTopY)

            polygon[self.IndexLT] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightTopY)
            polygon[self.IndexLB] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightBottomY)
            polygon[self.IndexRT] = QtCore.QPointF(R.right() - 4,
                                                   newLeftRightTopY)
            polygon[self.IndexRB] = QtCore.QPointF(R.right() - 4,
                                                   newLeftRightBottomY)
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                   R.top() + 4)
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                   R.top() + 4)
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                   R.bottom() - 4)
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                   R.bottom() - 4)
            polygon[self.IndexEE] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightTopY)

        elif self.mp_Handle == self.HandleTM:

            fromY = self.mp_Bound.top()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toY = snapF(toY, size, -4, snap)
            D.setY(toY - fromY)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            newSide = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSide / 2
            newLeftRightTopY = (R.y() + R.height() / 2) - newSide / 2

            selection[self.IndexTL] = QtCore.QPointF(
                background[self.IndexTL].x(), R.top())
            selection[self.IndexTR] = QtCore.QPointF(
                background[self.IndexTR].x(), R.top())
            selection[self.IndexLB] = QtCore.QPointF(
                background[self.IndexLB].x(), newLeftRightBottomY)
            selection[self.IndexRB] = QtCore.QPointF(
                background[self.IndexRB].x(), newLeftRightBottomY)
            selection[self.IndexLT] = QtCore.QPointF(
                background[self.IndexLT].x(), newLeftRightTopY)
            selection[self.IndexRT] = QtCore.QPointF(
                background[self.IndexRT].x(), newLeftRightTopY)
            selection[self.IndexEE] = QtCore.QPointF(
                background[self.IndexEE].x(), newLeftRightTopY)

            background[self.IndexTL] = QtCore.QPointF(
                background[self.IndexTL].x(), R.top())
            background[self.IndexTR] = QtCore.QPointF(
                background[self.IndexTR].x(), R.top())
            background[self.IndexLB] = QtCore.QPointF(
                background[self.IndexLB].x(), newLeftRightBottomY)
            background[self.IndexRB] = QtCore.QPointF(
                background[self.IndexRB].x(), newLeftRightBottomY)
            background[self.IndexLT] = QtCore.QPointF(
                background[self.IndexLT].x(), newLeftRightTopY)
            background[self.IndexRT] = QtCore.QPointF(
                background[self.IndexRT].x(), newLeftRightTopY)
            background[self.IndexEE] = QtCore.QPointF(
                background[self.IndexEE].x(), newLeftRightTopY)

            polygon[self.IndexTL] = QtCore.QPointF(polygon[self.IndexTL].x(),
                                                   R.top() + 4)
            polygon[self.IndexTR] = QtCore.QPointF(polygon[self.IndexTR].x(),
                                                   R.top() + 4)
            polygon[self.IndexLB] = QtCore.QPointF(polygon[self.IndexLB].x(),
                                                   newLeftRightBottomY)
            polygon[self.IndexRB] = QtCore.QPointF(polygon[self.IndexRB].x(),
                                                   newLeftRightBottomY)
            polygon[self.IndexLT] = QtCore.QPointF(polygon[self.IndexLT].x(),
                                                   newLeftRightTopY)
            polygon[self.IndexRT] = QtCore.QPointF(polygon[self.IndexRT].x(),
                                                   newLeftRightTopY)
            polygon[self.IndexEE] = QtCore.QPointF(polygon[self.IndexEE].x(),
                                                   newLeftRightTopY)

        elif self.mp_Handle == self.HandleTR:

            fromX = self.mp_Bound.right()
            fromY = self.mp_Bound.top()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, +4, snap)
            toY = snapF(toY, size, -4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            newSideY = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newSideX = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSideY / 2
            newLeftRightTopY = (R.y() + R.height() / 2) - newSideY / 2
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSideX / 2
            newTopBottomRightX = (R.x() + R.width() / 2) + newSideX / 2

            selection[self.IndexLT] = QtCore.QPointF(R.left(),
                                                     newLeftRightTopY)
            selection[self.IndexLB] = QtCore.QPointF(R.left(),
                                                     newLeftRightBottomY)
            selection[self.IndexRT] = QtCore.QPointF(R.right(),
                                                     newLeftRightTopY)
            selection[self.IndexRB] = QtCore.QPointF(R.right(),
                                                     newLeftRightBottomY)
            selection[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                     R.top())
            selection[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                     R.top())
            selection[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                     R.bottom())
            selection[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                     R.bottom())
            selection[self.IndexEE] = QtCore.QPointF(R.left(),
                                                     newLeftRightTopY)

            background[self.IndexLT] = QtCore.QPointF(R.left(),
                                                      newLeftRightTopY)
            background[self.IndexLB] = QtCore.QPointF(R.left(),
                                                      newLeftRightBottomY)
            background[self.IndexRT] = QtCore.QPointF(R.right(),
                                                      newLeftRightTopY)
            background[self.IndexRB] = QtCore.QPointF(R.right(),
                                                      newLeftRightBottomY)
            background[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                      R.top())
            background[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                      R.top())
            background[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                      R.bottom())
            background[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                      R.bottom())
            background[self.IndexEE] = QtCore.QPointF(R.left(),
                                                      newLeftRightTopY)

            polygon[self.IndexLT] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightTopY)
            polygon[self.IndexLB] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightBottomY)
            polygon[self.IndexRT] = QtCore.QPointF(R.right() - 4,
                                                   newLeftRightTopY)
            polygon[self.IndexRB] = QtCore.QPointF(R.right() - 4,
                                                   newLeftRightBottomY)
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                   R.top() + 4)
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                   R.top() + 4)
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                   R.bottom() - 4)
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                   R.bottom() - 4)
            polygon[self.IndexEE] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightTopY)

        elif self.mp_Handle == self.HandleML:

            fromX = self.mp_Bound.left()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toX = snapF(toX, size, -4, snap)
            D.setX(toX - fromX)
            R.setLeft(toX)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())

            newSide = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSide / 2
            newTopBottomRightX = (R.x() + R.width() / 2) + newSide / 2

            selection[self.IndexLT] = QtCore.QPointF(
                R.left(), selection[self.IndexLT].y())
            selection[self.IndexLB] = QtCore.QPointF(
                R.left(), selection[self.IndexLB].y())
            selection[self.IndexEE] = QtCore.QPointF(
                R.left(), selection[self.IndexEE].y())
            selection[self.IndexTL] = QtCore.QPointF(
                newTopBottomLeftX, selection[self.IndexTL].y())
            selection[self.IndexTR] = QtCore.QPointF(
                newTopBottomRightX, selection[self.IndexTR].y())
            selection[self.IndexBL] = QtCore.QPointF(
                newTopBottomLeftX, selection[self.IndexBL].y())
            selection[self.IndexBR] = QtCore.QPointF(
                newTopBottomRightX, selection[self.IndexBR].y())

            background[self.IndexLT] = QtCore.QPointF(
                R.left(), background[self.IndexLT].y())
            background[self.IndexLB] = QtCore.QPointF(
                R.left(), background[self.IndexLB].y())
            background[self.IndexEE] = QtCore.QPointF(
                R.left(), background[self.IndexEE].y())
            background[self.IndexTL] = QtCore.QPointF(
                newTopBottomLeftX, background[self.IndexTL].y())
            background[self.IndexTR] = QtCore.QPointF(
                newTopBottomRightX, background[self.IndexTR].y())
            background[self.IndexBL] = QtCore.QPointF(
                newTopBottomLeftX, background[self.IndexBL].y())
            background[self.IndexBR] = QtCore.QPointF(
                newTopBottomRightX, background[self.IndexBR].y())

            polygon[self.IndexLT] = QtCore.QPointF(R.left() + 4,
                                                   polygon[self.IndexLT].y())
            polygon[self.IndexLB] = QtCore.QPointF(R.left() + 4,
                                                   polygon[self.IndexLB].y())
            polygon[self.IndexEE] = QtCore.QPointF(R.left() + 4,
                                                   polygon[self.IndexEE].y())
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                   polygon[self.IndexTL].y())
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                   polygon[self.IndexTR].y())
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                   polygon[self.IndexBL].y())
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                   polygon[self.IndexBR].y())

        elif self.mp_Handle == self.HandleMR:

            fromX = self.mp_Bound.right()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toX = snapF(toX, size, +4, snap)
            D.setX(toX - fromX)
            R.setRight(toX)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())

            newSide = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newTopBottomRightX = (R.x() + R.width() / 2) + newSide / 2
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSide / 2

            selection[self.IndexRT] = QtCore.QPointF(
                R.right(), selection[self.IndexRT].y())
            selection[self.IndexRB] = QtCore.QPointF(
                R.right(), selection[self.IndexRB].y())
            selection[self.IndexTL] = QtCore.QPointF(
                newTopBottomLeftX, selection[self.IndexTL].y())
            selection[self.IndexTR] = QtCore.QPointF(
                newTopBottomRightX, selection[self.IndexTR].y())
            selection[self.IndexBL] = QtCore.QPointF(
                newTopBottomLeftX, selection[self.IndexBL].y())
            selection[self.IndexBR] = QtCore.QPointF(
                newTopBottomRightX, selection[self.IndexBR].y())

            background[self.IndexRT] = QtCore.QPointF(
                R.right(), background[self.IndexRT].y())
            background[self.IndexRB] = QtCore.QPointF(
                R.right(), background[self.IndexRB].y())
            background[self.IndexTL] = QtCore.QPointF(
                newTopBottomLeftX, background[self.IndexTL].y())
            background[self.IndexTR] = QtCore.QPointF(
                newTopBottomRightX, background[self.IndexTR].y())
            background[self.IndexBL] = QtCore.QPointF(
                newTopBottomLeftX, background[self.IndexBL].y())
            background[self.IndexBR] = QtCore.QPointF(
                newTopBottomRightX, background[self.IndexBR].y())

            polygon[self.IndexRT] = QtCore.QPointF(R.right() - 4,
                                                   polygon[self.IndexRT].y())
            polygon[self.IndexRB] = QtCore.QPointF(R.right() - 4,
                                                   polygon[self.IndexRB].y())
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                   polygon[self.IndexTL].y())
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                   polygon[self.IndexTR].y())
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                   polygon[self.IndexBL].y())
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                   polygon[self.IndexBR].y())

        elif self.mp_Handle == self.HandleBL:

            fromX = self.mp_Bound.left()
            fromY = self.mp_Bound.bottom()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, -4, snap)
            toY = snapF(toY, size, +4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            newSideY = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newSideX = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSideY / 2
            newLeftRightTopY = (R.y() + R.height() / 2) - newSideY / 2
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSideX / 2
            newTopBottomRightX = (R.x() + R.width() / 2) + newSideX / 2

            selection[self.IndexLT] = QtCore.QPointF(R.left(),
                                                     newLeftRightTopY)
            selection[self.IndexLB] = QtCore.QPointF(R.left(),
                                                     newLeftRightBottomY)
            selection[self.IndexRT] = QtCore.QPointF(R.right(),
                                                     newLeftRightTopY)
            selection[self.IndexRB] = QtCore.QPointF(R.right(),
                                                     newLeftRightBottomY)
            selection[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                     R.top())
            selection[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                     R.top())
            selection[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                     R.bottom())
            selection[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                     R.bottom())
            selection[self.IndexEE] = QtCore.QPointF(R.left(),
                                                     newLeftRightTopY)

            background[self.IndexLT] = QtCore.QPointF(R.left(),
                                                      newLeftRightTopY)
            background[self.IndexLB] = QtCore.QPointF(R.left(),
                                                      newLeftRightBottomY)
            background[self.IndexRT] = QtCore.QPointF(R.right(),
                                                      newLeftRightTopY)
            background[self.IndexRB] = QtCore.QPointF(R.right(),
                                                      newLeftRightBottomY)
            background[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                      R.top())
            background[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                      R.top())
            background[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                      R.bottom())
            background[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                      R.bottom())
            background[self.IndexEE] = QtCore.QPointF(R.left(),
                                                      newLeftRightTopY)

            polygon[self.IndexLT] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightTopY)
            polygon[self.IndexLB] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightBottomY)
            polygon[self.IndexRT] = QtCore.QPointF(R.right() - 4,
                                                   newLeftRightTopY)
            polygon[self.IndexRB] = QtCore.QPointF(R.right() - 4,
                                                   newLeftRightBottomY)
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                   R.top() + 4)
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                   R.top() + 4)
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                   R.bottom() - 4)
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                   R.bottom() - 4)
            polygon[self.IndexEE] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightTopY)

        elif self.mp_Handle == self.HandleBM:

            fromY = self.mp_Bound.bottom()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toY = snapF(toY, size, +4, snap)
            D.setY(toY - fromY)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            newSide = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightTopY = (R.y() + R.height() / 2) - newSide / 2
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSide / 2

            selection[self.IndexBL] = QtCore.QPointF(
                selection[self.IndexBL].x(), R.bottom())
            selection[self.IndexBR] = QtCore.QPointF(
                selection[self.IndexBR].x(), R.bottom())
            selection[self.IndexLB] = QtCore.QPointF(
                selection[self.IndexLB].x(), newLeftRightBottomY)
            selection[self.IndexRB] = QtCore.QPointF(
                selection[self.IndexRB].x(), newLeftRightBottomY)
            selection[self.IndexLT] = QtCore.QPointF(
                selection[self.IndexLT].x(), newLeftRightTopY)
            selection[self.IndexRT] = QtCore.QPointF(
                selection[self.IndexRT].x(), newLeftRightTopY)
            selection[self.IndexEE] = QtCore.QPointF(
                selection[self.IndexEE].x(), newLeftRightTopY)

            background[self.IndexBL] = QtCore.QPointF(
                background[self.IndexBL].x(), R.bottom())
            background[self.IndexBR] = QtCore.QPointF(
                background[self.IndexBR].x(), R.bottom())
            background[self.IndexLB] = QtCore.QPointF(
                background[self.IndexLB].x(), newLeftRightBottomY)
            background[self.IndexRB] = QtCore.QPointF(
                background[self.IndexRB].x(), newLeftRightBottomY)
            background[self.IndexLT] = QtCore.QPointF(
                background[self.IndexLT].x(), newLeftRightTopY)
            background[self.IndexRT] = QtCore.QPointF(
                background[self.IndexRT].x(), newLeftRightTopY)
            background[self.IndexEE] = QtCore.QPointF(
                background[self.IndexEE].x(), newLeftRightTopY)

            polygon[self.IndexBL] = QtCore.QPointF(polygon[self.IndexBL].x(),
                                                   R.bottom() - 4)
            polygon[self.IndexBR] = QtCore.QPointF(polygon[self.IndexBR].x(),
                                                   R.bottom() - 4)
            polygon[self.IndexLB] = QtCore.QPointF(polygon[self.IndexLB].x(),
                                                   newLeftRightBottomY)
            polygon[self.IndexRB] = QtCore.QPointF(polygon[self.IndexRB].x(),
                                                   newLeftRightBottomY)
            polygon[self.IndexLT] = QtCore.QPointF(polygon[self.IndexLT].x(),
                                                   newLeftRightTopY)
            polygon[self.IndexRT] = QtCore.QPointF(polygon[self.IndexRT].x(),
                                                   newLeftRightTopY)
            polygon[self.IndexEE] = QtCore.QPointF(polygon[self.IndexEE].x(),
                                                   newLeftRightTopY)

        elif self.mp_Handle == self.HandleBR:

            fromX = self.mp_Bound.right()
            fromY = self.mp_Bound.bottom()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, +4, snap)
            toY = snapF(toY, size, +4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            newSideY = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newSideX = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSideY / 2
            newLeftRightTopY = (R.y() + R.height() / 2) - newSideY / 2
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSideX / 2
            newTopBottomRightX = (R.x() + R.width() / 2) + newSideX / 2

            selection[self.IndexLT] = QtCore.QPointF(R.left(),
                                                     newLeftRightTopY)
            selection[self.IndexLB] = QtCore.QPointF(R.left(),
                                                     newLeftRightBottomY)
            selection[self.IndexRT] = QtCore.QPointF(R.right(),
                                                     newLeftRightTopY)
            selection[self.IndexRB] = QtCore.QPointF(R.right(),
                                                     newLeftRightBottomY)
            selection[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                     R.top())
            selection[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                     R.top())
            selection[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                     R.bottom())
            selection[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                     R.bottom())
            selection[self.IndexEE] = QtCore.QPointF(R.left(),
                                                     newLeftRightTopY)

            background[self.IndexLT] = QtCore.QPointF(R.left(),
                                                      newLeftRightTopY)
            background[self.IndexLB] = QtCore.QPointF(R.left(),
                                                      newLeftRightBottomY)
            background[self.IndexRT] = QtCore.QPointF(R.right(),
                                                      newLeftRightTopY)
            background[self.IndexRB] = QtCore.QPointF(R.right(),
                                                      newLeftRightBottomY)
            background[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                      R.top())
            background[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                      R.top())
            background[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                      R.bottom())
            background[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                      R.bottom())
            background[self.IndexEE] = QtCore.QPointF(R.left(),
                                                      newLeftRightTopY)

            polygon[self.IndexLT] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightTopY)
            polygon[self.IndexLB] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightBottomY)
            polygon[self.IndexRT] = QtCore.QPointF(R.right() - 4,
                                                   newLeftRightTopY)
            polygon[self.IndexRB] = QtCore.QPointF(R.right() - 4,
                                                   newLeftRightBottomY)
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                   R.top() + 4)
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                   R.top() + 4)
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                   R.bottom() - 4)
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                   R.bottom() - 4)
            polygon[self.IndexEE] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightTopY)

        self.background.setGeometry(background)
        self.selection.setGeometry(selection)
        self.polygon.setGeometry(polygon)

        self.updateNode(selected=True,
                        handle=self.mp_Handle,
                        anchors=(self.mp_Data, D))
        self.updateTextPos(moved=moved)

    def setIdentity(self, identity):
        """
        Set the identity of the current node.
        :type identity: Identity
        """
        pass

    def setText(self, text):
        """
        Set the label text.
        :type text: str
        """
        self.label.setText(text)
        self.label.setAlignment(QtCore.Qt.AlignCenter)

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        self.label.setPos(pos)

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        for polygon in self.handles:
            path.addEllipse(polygon.geometry())
        return path

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        return self.label.text()

    def textPos(self):
        """
        Returns the current label position in item coordinates.
        :rtype: QPointF
        """
        return self.label.pos()

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        self.label.updatePos(*args, **kwargs)

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        polygon = self.polygon.geometry()
        return polygon[self.IndexRT].x() - polygon[self.IndexLT].x()

    def __repr__(self):
        """
        Returns repr(self).
        """
        return '{0}:{1}:{2}'.format(self.__class__.__name__, self.text(),
                                    self.id)
Exemple #3
0
class ConceptNode(AbstractResizableNode):
    """
    This class implements the 'Concept' node.
    """
    DefaultBrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.0, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
    Identities = {Identity.Concept}
    Type = Item.ConceptNode

    def __init__(self, width=110, height=50, brush=None, **kwargs):
        """
        Initialize the node.
        :type width: int
        :type height: int
        :type brush: QBrush
        """
        super().__init__(**kwargs)
        w = max(width, 110)
        h = max(height, 50)
        brush = brush or ConceptNode.DefaultBrush
        pen = ConceptNode.DefaultPen
        self.background = Polygon(QtCore.QRectF(-(w + 8) / 2, -(h + 8) / 2, w + 8, h + 8))
        self.selection = Polygon(QtCore.QRectF(-(w + 8) / 2, -(h + 8) / 2, w + 8, h + 8))
        self.polygon = Polygon(QtCore.QRectF(-w / 2, -h / 2, w, h), brush, pen)
        self.label = NodeLabel(template='concept', pos=self.center, parent=self)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.updateNode()
        self.updateTextPos()

    #############################################
    #   INTERFACE
    #################################

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QtCore.QRectF
        """
        return self.selection.geometry()

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        node = diagram.factory.create(self.type(), **{
            'id': self.id,
            'brush': self.brush(),
            'height': self.height(),
            'width': self.width()
        })
        node.setPos(self.pos())
        node.setText(self.text())
        node.setTextPos(node.mapFromScene(self.mapToScene(self.textPos())))
        return node

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        return self.polygon.geometry().height()

    def identity(self):
        """
        Returns the identity of the current node.
        :rtype: Identity
        """
        return Identity.Concept

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawRect(self.selection.geometry())
        # SYNTAX VALIDATION
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawRect(self.background.geometry())
        # ITEM SHAPE
        painter.setPen(self.polygon.pen())
        painter.setBrush(self.polygon.brush())
        painter.drawRect(self.polygon.geometry())
        # RESIZE HANDLES
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        for polygon in self.handles:
            painter.setPen(polygon.pen())
            painter.setBrush(polygon.brush())
            painter.drawEllipse(polygon.geometry())

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addRect(self.polygon.geometry())
        return path

    def resize(self, mousePos):
        """
        Handle the interactive resize of the shape.
        :type mousePos: QtCore.QPointF
        """
        snap = self.session.action('toggle_grid').isChecked()
        size = self.diagram.GridSize
        moved = self.label.isMoved()
        background = self.background.geometry()
        selection = self.selection.geometry()
        polygon = self.polygon.geometry()

        R = QtCore.QRectF(self.boundingRect())
        D = QtCore.QPointF(0, 0)

        mbrh = 58
        mbrw = 118

        self.prepareGeometryChange()

        if self.mp_Handle == self.HandleTL:

            fromX = self.mp_Bound.left()
            fromY = self.mp_Bound.top()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, -4, snap)
            toY = snapF(toY, size, -4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            background.setLeft(R.left())
            background.setTop(R.top())
            selection.setLeft(R.left())
            selection.setTop(R.top())
            polygon.setLeft(R.left() + 4)
            polygon.setTop(R.top() + 4)

        elif self.mp_Handle == self.HandleTM:

            fromY = self.mp_Bound.top()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toY = snapF(toY, size, -4, snap)
            D.setY(toY - fromY)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            background.setTop(R.top())
            selection.setTop(R.top())
            polygon.setTop(R.top() + 4)

        elif self.mp_Handle == self.HandleTR:

            fromX = self.mp_Bound.right()
            fromY = self.mp_Bound.top()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, +4, snap)
            toY = snapF(toY, size, -4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            background.setRight(R.right())
            background.setTop(R.top())
            selection.setRight(R.right())
            selection.setTop(R.top())
            polygon.setRight(R.right() - 4)
            polygon.setTop(R.top() + 4)

        elif self.mp_Handle == self.HandleML:

            fromX = self.mp_Bound.left()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toX = snapF(toX, size, -4, snap)
            D.setX(toX - fromX)
            R.setLeft(toX)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())

            background.setLeft(R.left())
            selection.setLeft(R.left())
            polygon.setLeft(R.left() + 4)

        elif self.mp_Handle == self.HandleMR:

            fromX = self.mp_Bound.right()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toX = snapF(toX, size, +4, snap)
            D.setX(toX - fromX)
            R.setRight(toX)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())

            background.setRight(R.right())
            selection.setRight(R.right())
            polygon.setRight(R.right() - 4)

        elif self.mp_Handle == self.HandleBL:

            fromX = self.mp_Bound.left()
            fromY = self.mp_Bound.bottom()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, -4, snap)
            toY = snapF(toY, size, +4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            background.setLeft(R.left())
            background.setBottom(R.bottom())
            selection.setLeft(R.left())
            selection.setBottom(R.bottom())
            polygon.setLeft(R.left() + 4)
            polygon.setBottom(R.bottom() - 4)

        elif self.mp_Handle == self.HandleBM:

            fromY = self.mp_Bound.bottom()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toY = snapF(toY, size, +4, snap)
            D.setY(toY - fromY)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            background.setBottom(R.bottom())
            selection.setBottom(R.bottom())
            polygon.setBottom(R.bottom() - 4)

        elif self.mp_Handle == self.HandleBR:

            fromX = self.mp_Bound.right()
            fromY = self.mp_Bound.bottom()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, +4, snap)
            toY = snapF(toY, size, +4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            background.setRight(R.right())
            background.setBottom(R.bottom())
            selection.setRight(R.right())
            selection.setBottom(R.bottom())
            polygon.setRight(R.right() - 4)
            polygon.setBottom(R.bottom() - 4)

        self.background.setGeometry(background)
        self.selection.setGeometry(selection)
        self.polygon.setGeometry(polygon)

        self.updateNode(selected=True, handle=self.mp_Handle, anchors=(self.mp_Data, D))
        self.updateTextPos(moved=moved)

    def setIdentity(self, identity):
        """
        Set the identity of the current node.
        :type identity: Identity
        """
        pass

    def setText(self, text):
        """
        Set the label text.
        :type text: str
        """
        self.label.setText(text)
        self.label.setAlignment(QtCore.Qt.AlignCenter)

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        self.label.setPos(pos)

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addRect(self.polygon.geometry())
        for polygon in self.handles:
            path.addEllipse(polygon.geometry())
        return path

    def special(self):
        """
        Returns the special type of this node.
        :rtype: Special
        """
        return Special.forValue(self.text())

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        return self.label.text()

    def textPos(self):
        """
        Returns the current label position in item coordinates.
        :rtype: QPointF
        """
        return self.label.pos()

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        self.label.updatePos(*args, **kwargs)

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        return self.polygon.geometry().width()

    def __repr__(self):
        """
        Returns repr(self).
        """
        return '{0}:{1}:{2}'.format(self.__class__.__name__, self.text(), self.id)
Exemple #4
0
class OperatorNode(AbstractNode):
    """
    This is the base class for operator nodes.
    """
    __metaclass__ = ABCMeta

    DefaultBrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1,
                            QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                            QtCore.Qt.RoundJoin)

    IndexML = 0
    IndexBL = 1
    IndexBR = 2
    IndexMR = 3
    IndexTR = 4
    IndexTL = 5
    IndexEE = 6

    def __init__(self, width=50, height=30, brush=None, **kwargs):
        """
        Initialize the node.
        :type width: int
        :type height: int
        :type brush: QBrush
        """
        super().__init__(**kwargs)

        createPolygon = lambda x, y: QtGui.QPolygonF([
            QtCore.QPointF(-x / 2, 0),
            QtCore.QPointF(-x / 2 + 6, +y / 2),
            QtCore.QPointF(+x / 2 - 6, +y / 2),
            QtCore.QPointF(+x / 2, 0),
            QtCore.QPointF(+x / 2 - 6, -y / 2),
            QtCore.QPointF(-x / 2 + 6, -y / 2),
            QtCore.QPointF(-x / 2, 0),
        ])

        self.background = Polygon(createPolygon(58, 38))
        self.selection = Polygon(createPolygon(58, 38))
        self.polygon = Polygon(createPolygon(50, 30), brush
                               or OperatorNode.DefaultBrush,
                               OperatorNode.DefaultPen)

    #############################################
    #   INTERFACE
    #################################

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QtCore.QRectF
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.selection.geometry())
        return path.boundingRect()

    @abstractmethod
    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        pass

    def definition(self):
        """
        Returns the list of nodes which contribute to the definition of this very node.
        :rtype: set
        """
        return set(
            self.incomingNodes(
                filter_on_edges=lambda x: x.type() is Item.InputEdge))

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        polygon = self.polygon.geometry()
        return polygon[self.IndexBL].y() - polygon[self.IndexTL].y()

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawPolygon(self.selection.geometry())
        # SYNTAX VALIDATION
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawPolygon(self.background.geometry())
        # ITEM SHAPE
        painter.setPen(self.polygon.pen())
        painter.setBrush(self.polygon.brush())
        painter.drawPolygon(self.polygon.geometry())

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        return path

    def setText(self, text):
        """
        Set the label text.
        :type text: str
        """
        pass

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        pass

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        return path

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        pass

    def textPos(self):
        """
        Returns the current label position in item coordinates.
        :rtype: QPointF
        """
        pass

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        pass

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        polygon = self.polygon.geometry()
        return polygon[self.IndexMR].x() - polygon[self.IndexML].x()
class PropertyAssertionNode(AbstractNode):
    """
    This class implements the 'Property Assertion' node.
    """
    DefaultBrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.0,
                            QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                            QtCore.Qt.RoundJoin)
    Identities = {
        Identity.RoleInstance, Identity.AttributeInstance, Identity.Neutral
    }
    Type = Item.PropertyAssertionNode

    def __init__(self, width=52, height=30, brush=None, inputs=None, **kwargs):
        """
        Initialize the node.
        :type width: int
        :type height: int
        :type brush: QBrush
        :type inputs: DistinctList
        """
        super().__init__(**kwargs)
        brush = PropertyAssertionNode.DefaultBrush
        pen = PropertyAssertionNode.DefaultPen
        self.inputs = inputs or DistinctList()
        self.background = Polygon(QtCore.QRectF(-34, -19, 68, 38))
        self.selection = Polygon(QtCore.QRectF(-34, -19, 68, 38))
        self.polygon = Polygon(QtCore.QRectF(-26, -15, 52, 30), brush, pen)

    #############################################
    #   INTERFACE
    #################################

    def addEdge(self, edge):
        """
        Add the given edge to the current node.
        :type edge: AbstractEdge
        """
        super().addEdge(edge)
        if edge.type() is Item.InputEdge and edge.target is self:
            self.inputs.append(edge.id)
            edge.updateEdge()

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QtCore.QRectF
        """
        return self.selection.geometry()

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        kwargs = {
            'id': self.id,
            'height': self.height(),
            'width': self.width()
        }
        node = diagram.factory.create(self.type(), **kwargs)
        node.setPos(self.pos())
        return node

    def definition(self):
        """
        Returns the list of nodes which contribute to the definition of this very node.
        :rtype: set
        """
        return set(
            self.incomingNodes(
                filter_on_edges=lambda x: x.type() is Item.InputEdge))

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        return self.polygon.geometry().height()

    def identify(self):
        """
        Perform the node identification step for this PropertyAssertion node.
        The identity of the node is calculated as follows:

        * If the node is targeting a Role with a membership edge => Identity == RoleInstance
        * If the node is targeting an Attribute with a membership edge => Identity == AttributeInstance

        else

        * If the node has 2 individuals as inputs => Identity == RoleInstance
        * If the node has 1 individual and 1 value as inputs => Identity == AttributeInstance

        In both the cases, whether we establish or not an idendity for this node,
        we mark it for EXCLUSION from the STRONG and WEAK sets. This is due to the
        PropertyAssertion node being used to perform assertions at ABox level
        while every other node in the graph is used at TBox level. Additionally we
        discard the inputs of this node from the STRONG set because they are either
        Individual or Value nodes and they are not needed to compute the final identity
        for all the WEAK nodes being examined during the identification process.
        :rtype: tuple
        """
        f1 = lambda x: x.type() is Item.MembershipEdge
        f2 = lambda x: x.type(
        ) in {Item.RoleNode, Item.RoleInverseNode, Item.AttributeNode}
        f3 = lambda x: x.type() is Item.InputEdge
        f4 = lambda x: x.type() is Item.IndividualNode
        f5 = lambda x: Identity.RoleInstance if x.identity(
        ) is Identity.Role else Identity.AttributeInstance
        f6 = lambda x: x.identity() is Identity.Value
        outgoing = self.outgoingNodes(filter_on_edges=f1, filter_on_nodes=f2)
        incoming = self.incomingNodes(filter_on_edges=f3, filter_on_nodes=f4)
        computed = Identity.Neutral
        # 1) USE MEMBERSHIP EDGE
        identities = set(map(f5, outgoing))
        if identities:
            computed = first(identities)
            if len(identities) > 1:
                computed = Identity.Unknown
        # 2) USE INPUT EDGES
        if computed is Identity.Neutral and len(incoming) >= 2:
            computed = Identity.RoleInstance
            if sum(map(f6, incoming)):
                computed = Identity.AttributeInstance
        self.setIdentity(computed)
        return set(), incoming, {self}

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawRoundedRect(self.selection.geometry(), 16, 16)
        # SYNTAX VALIDATION
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawRoundedRect(self.background.geometry(), 16, 16)
        # SHAPE
        painter.setPen(self.polygon.pen())
        painter.setBrush(self.polygon.brush())
        painter.drawRoundedRect(self.polygon.geometry(), 16, 16)

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addRoundedRect(self.polygon.geometry(), 16, 16)
        return path

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addRoundedRect(self.polygon.geometry(), 16, 16)
        return path

    def removeEdge(self, edge):
        """
        Remove the given edge from the current node.
        :type edge: AbstractEdge
        """
        super().removeEdge(edge)
        self.inputs.remove(edge.id)
        for i in self.inputs:
            try:
                edge = self.diagram.edge(i)
                edge.updateEdge()
            except KeyError:
                pass

    def setText(self, text):
        """
        Set the label text.
        :type text: str
        """
        pass

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        pass

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        pass

    def textPos(self):
        """
        Returns the current label position in item coordinates.
        :rtype: QPointF
        """
        pass

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        pass

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        return self.polygon.geometry().width()
Exemple #6
0
class RestrictionNode(AbstractNode):
    """
    This is the base class for all the Restriction nodes.
    """
    __metaclass__ = ABCMeta

    DefaultBrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.0,
                            QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                            QtCore.Qt.RoundJoin)

    def __init__(self, width=20, height=20, brush=None, **kwargs):
        """
        Initialize the node.
        :type width: int
        :type height: int
        :type brush: QBrush
        """
        super().__init__(**kwargs)
        brush = brush or RestrictionNode.DefaultBrush
        pen = RestrictionNode.DefaultPen
        self.background = Polygon(QtCore.QRectF(-14, -14, 28, 28))
        self.selection = Polygon(QtCore.QRectF(-14, -14, 28, 28))
        self.polygon = Polygon(QtCore.QRectF(-10, -10, 20, 20), brush, pen)
        self.label = NodeLabel(
            Restriction.Exists.toString(),
            pos=lambda: self.center() - QtCore.QPointF(0, 22),
            editable=False,
            parent=self)

    #############################################
    #   INTERFACE
    #################################

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QtCore.QRectF
        """
        return self.selection.geometry()

    def cardinality(self, *args):
        """
        Returns the cardinality of the node.
        :rtype: T <= int|dict
        """
        cardinality = {'min': None, 'max': None}
        match = RE_CARDINALITY.match(self.text())
        if match:
            if match.group('min') != '-':
                cardinality['min'] = int(match.group('min'))
            if match.group('max') != '-':
                cardinality['max'] = int(match.group('max'))
        if args:
            cardinality = {k: v for k, v in cardinality.items() if k in args}
            if len(cardinality) == 1:
                cardinality = first(cardinality.values())
        return cardinality

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        node = diagram.factory.create(
            self.type(), **{
                'id': self.id,
                'height': self.height(),
                'width': self.width()
            })
        node.setPos(self.pos())
        node.setText(self.text())
        node.setTextPos(node.mapFromScene(self.mapToScene(self.textPos())))
        return node

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        return self.polygon.geometry().height()

    def isRestrictionQualified(self):
        """
        Returna True if this node expresses a qualified restriction (exists R.C), False otherwise.
        :rtype: bool
        """
        f1 = lambda x: x.type() is Item.InputEdge
        f2 = lambda x: x.identity() in {Identity.Concept, Identity.Role}
        f3 = lambda x: x.identity(
        ) in {Identity.Attribute, Identity.ValueDomain}
        f4 = lambda x: x.identity() is Identity.Concept
        if self.restriction() in {
                Restriction.Cardinality, Restriction.Exists, Restriction.Forall
        }:
            # CHECK FOR ROLE QUALIFIED RESTRICTION
            collection = self.incomingNodes(filter_on_edges=f1,
                                            filter_on_nodes=f2)
            if len(collection) >= 2:
                node = first(collection, filter_on_item=f4)
                if node and Special.valueOf(node.text()) is not Special.Top:
                    return True
            # CHECK FOR ATTRIBUTE QUALIFIED RESTRICTION
            return len(
                self.incomingNodes(filter_on_edges=f1,
                                   filter_on_nodes=f3)) >= 2
        return False

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawRect(self.selection.geometry())
        # SYNTAX VALIDATION
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawRect(self.background.geometry())
        # ITEM SHAPE
        painter.setPen(self.polygon.pen())
        painter.setBrush(self.polygon.brush())
        painter.drawRect(self.polygon.geometry())

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addRect(self.polygon.geometry())
        return path

    def restriction(self):
        """
        Returns the restriction type of the node.
        :rtype: Restriction
        """
        return Restriction.forLabel(self.text())

    def setText(self, text):
        """
        Set the label text.
        Will additionally parse the given value checking for a consistent restriction type.
        :type text: str
        """
        restriction = Restriction.forLabel(text)
        if not restriction:
            text = Restriction.Exists.toString()
        self.label.setText(text)

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        self.label.setPos(pos)

    def shape(self, *args, **kwargs):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addRect(self.polygon.geometry())
        return path

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        return self.label.text()

    def textPos(self):
        """
        Returns the current label position.
        :rtype: QPointF
        """
        return self.label.pos()

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        return self.polygon.geometry().width()

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        self.label.updatePos(*args, **kwargs)
Exemple #7
0
class OperatorNode(AbstractNode):
    """
    This is the base class for operator nodes.
    """
    __metaclass__ = ABCMeta

    DefaultBrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)

    IndexML = 0
    IndexBL = 1
    IndexBR = 2
    IndexMR = 3
    IndexTR = 4
    IndexTL = 5
    IndexEE = 6

    def __init__(self, width=50, height=30, brush=None, **kwargs):
        """
        Initialize the node.
        :type width: int
        :type height: int
        :type brush: QBrush
        """
        super().__init__(**kwargs)

        createPolygon = lambda x, y: QtGui.QPolygonF([
            QtCore.QPointF(-x / 2, 0),
            QtCore.QPointF(-x / 2 + 6, +y / 2),
            QtCore.QPointF(+x / 2 - 6, +y / 2),
            QtCore.QPointF(+x / 2, 0),
            QtCore.QPointF(+x / 2 - 6, -y / 2),
            QtCore.QPointF(-x / 2 + 6, -y / 2),
            QtCore.QPointF(-x / 2, 0),
        ])

        self.background = Polygon(createPolygon(58, 38))
        self.selection = Polygon(createPolygon(58, 38))
        self.polygon = Polygon(createPolygon(50, 30), brush or OperatorNode.DefaultBrush, OperatorNode.DefaultPen)

    #############################################
    #   INTERFACE
    #################################

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QtCore.QRectF
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.selection.geometry())
        return path.boundingRect()

    @abstractmethod
    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        pass

    def definition(self):
        """
        Returns the list of nodes which contribute to the definition of this very node.
        :rtype: set
        """
        return set(self.incomingNodes(filter_on_edges=lambda x: x.type() is Item.InputEdge))

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        polygon = self.polygon.geometry()
        return polygon[self.IndexBL].y() - polygon[self.IndexTL].y()

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawPolygon(self.selection.geometry())
        # SYNTAX VALIDATION
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawPolygon(self.background.geometry())
        # ITEM SHAPE
        painter.setPen(self.polygon.pen())
        painter.setBrush(self.polygon.brush())
        painter.drawPolygon(self.polygon.geometry())

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        return path

    def setText(self, text):
        """
        Set the label text.
        :type text: str
        """
        pass

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        pass

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        return path

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        pass

    def textPos(self):
        """
        Returns the current label position in item coordinates.
        :rtype: QPointF
        """
        pass

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        pass

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        polygon = self.polygon.geometry()
        return polygon[self.IndexMR].x() - polygon[self.IndexML].x()
Exemple #8
0
class ConceptNode(AbstractResizableNode):
    """
    This class implements the 'Concept' node.
    """
    DefaultBrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.0, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
    Identities = {Identity.Concept}
    Type = Item.ConceptNode

    def __init__(self, width=110, height=50, brush=None, **kwargs):
        """
        Initialize the node.
        :type width: int
        :type height: int
        :type brush: QBrush
        """
        super().__init__(**kwargs)
        w = max(width, 110)
        h = max(height, 50)
        brush = brush or ConceptNode.DefaultBrush
        pen = ConceptNode.DefaultPen
        self.background = Polygon(QtCore.QRectF(-(w + 8) / 2, -(h + 8) / 2, w + 8, h + 8))
        self.selection = Polygon(QtCore.QRectF(-(w + 8) / 2, -(h + 8) / 2, w + 8, h + 8))
        self.polygon = Polygon(QtCore.QRectF(-w / 2, -h / 2, w, h), brush, pen)
        self.label = NodeLabel(template='concept', pos=self.center, parent=self)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.updateNode()
        self.updateTextPos()

    #############################################
    #   INTERFACE
    #################################

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QtCore.QRectF
        """
        return self.selection.geometry()

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        node = diagram.factory.create(self.type(), **{
            'id': self.id,
            'brush': self.brush(),
            'height': self.height(),
            'width': self.width()
        })
        node.setPos(self.pos())
        node.setText(self.text())
        node.setTextPos(node.mapFromScene(self.mapToScene(self.textPos())))
        return node

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        return self.polygon.geometry().height()

    def identity(self):
        """
        Returns the identity of the current node.
        :rtype: Identity
        """
        return Identity.Concept

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawRect(self.selection.geometry())
        # SYNTAX VALIDATION
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawRect(self.background.geometry())
        # ITEM SHAPE
        painter.setPen(self.polygon.pen())
        painter.setBrush(self.polygon.brush())
        painter.drawRect(self.polygon.geometry())
        # RESIZE HANDLES
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        for polygon in self.handles:
            painter.setPen(polygon.pen())
            painter.setBrush(polygon.brush())
            painter.drawEllipse(polygon.geometry())

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addRect(self.polygon.geometry())
        return path

    def resize(self, mousePos):
        """
        Handle the interactive resize of the shape.
        :type mousePos: QtCore.QPointF
        """
        snap = self.session.action('toggle_grid').isChecked()
        size = self.diagram.GridSize
        moved = self.label.isMoved()
        background = self.background.geometry()
        selection = self.selection.geometry()
        polygon = self.polygon.geometry()

        R = QtCore.QRectF(self.boundingRect())
        D = QtCore.QPointF(0, 0)

        mbrh = 58
        mbrw = 118

        self.prepareGeometryChange()

        if self.mp_Handle == self.HandleTL:

            fromX = self.mp_Bound.left()
            fromY = self.mp_Bound.top()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, -4, snap)
            toY = snapF(toY, size, -4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            background.setLeft(R.left())
            background.setTop(R.top())
            selection.setLeft(R.left())
            selection.setTop(R.top())
            polygon.setLeft(R.left() + 4)
            polygon.setTop(R.top() + 4)

        elif self.mp_Handle == self.HandleTM:

            fromY = self.mp_Bound.top()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toY = snapF(toY, size, -4, snap)
            D.setY(toY - fromY)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            background.setTop(R.top())
            selection.setTop(R.top())
            polygon.setTop(R.top() + 4)

        elif self.mp_Handle == self.HandleTR:

            fromX = self.mp_Bound.right()
            fromY = self.mp_Bound.top()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, +4, snap)
            toY = snapF(toY, size, -4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            background.setRight(R.right())
            background.setTop(R.top())
            selection.setRight(R.right())
            selection.setTop(R.top())
            polygon.setRight(R.right() - 4)
            polygon.setTop(R.top() + 4)

        elif self.mp_Handle == self.HandleML:

            fromX = self.mp_Bound.left()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toX = snapF(toX, size, -4, snap)
            D.setX(toX - fromX)
            R.setLeft(toX)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())

            background.setLeft(R.left())
            selection.setLeft(R.left())
            polygon.setLeft(R.left() + 4)

        elif self.mp_Handle == self.HandleMR:

            fromX = self.mp_Bound.right()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toX = snapF(toX, size, +4, snap)
            D.setX(toX - fromX)
            R.setRight(toX)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())

            background.setRight(R.right())
            selection.setRight(R.right())
            polygon.setRight(R.right() - 4)

        elif self.mp_Handle == self.HandleBL:

            fromX = self.mp_Bound.left()
            fromY = self.mp_Bound.bottom()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, -4, snap)
            toY = snapF(toY, size, +4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            background.setLeft(R.left())
            background.setBottom(R.bottom())
            selection.setLeft(R.left())
            selection.setBottom(R.bottom())
            polygon.setLeft(R.left() + 4)
            polygon.setBottom(R.bottom() - 4)

        elif self.mp_Handle == self.HandleBM:

            fromY = self.mp_Bound.bottom()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toY = snapF(toY, size, +4, snap)
            D.setY(toY - fromY)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            background.setBottom(R.bottom())
            selection.setBottom(R.bottom())
            polygon.setBottom(R.bottom() - 4)

        elif self.mp_Handle == self.HandleBR:

            fromX = self.mp_Bound.right()
            fromY = self.mp_Bound.bottom()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, +4, snap)
            toY = snapF(toY, size, +4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            background.setRight(R.right())
            background.setBottom(R.bottom())
            selection.setRight(R.right())
            selection.setBottom(R.bottom())
            polygon.setRight(R.right() - 4)
            polygon.setBottom(R.bottom() - 4)

        self.background.setGeometry(background)
        self.selection.setGeometry(selection)
        self.polygon.setGeometry(polygon)

        self.updateNode(selected=True, handle=self.mp_Handle, anchors=(self.mp_Data, D))
        self.updateTextPos(moved=moved)

    def setIdentity(self, identity):
        """
        Set the identity of the current node.
        :type identity: Identity
        """
        pass

    def setText(self, text):
        """
        Set the label text.
        :type text: str
        """
        self.label.setText(text)
        self.label.setAlignment(QtCore.Qt.AlignCenter)

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        self.label.setPos(pos)

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addRect(self.polygon.geometry())
        for polygon in self.handles:
            path.addEllipse(polygon.geometry())
        return path

    def special(self):
        """
        Returns the special type of this node.
        :rtype: Special
        """
        return Special.valueOf(self.text())

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        return self.label.text()

    def textPos(self):
        """
        Returns the current label position in item coordinates.
        :rtype: QPointF
        """
        return self.label.pos()

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        self.label.updatePos(*args, **kwargs)

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        return self.polygon.geometry().width()

    def __repr__(self):
        """
        Returns repr(self).
        """
        return '{0}:{1}:{2}'.format(self.__class__.__name__, self.text(), self.id)
class EquivalenceEdge(AbstractEdge):
    """
    This class implements the 'Equivalence' edge.
    """
    Type = Item.EquivalenceEdge

    def __init__(self, **kwargs):
        """
        Initialize the edge.
        """
        super().__init__(**kwargs)
        self.tail = Polygon(QtGui.QPolygonF())

    #############################################
    #   INTERFACE
    #################################

    def boundingRect(self):
        """
        Returns the shape bounding rect.
        :rtype: QRectF
        """
        path = QtGui.QPainterPath()
        path.addPath(self.selection.geometry())
        path.addPolygon(self.head.geometry())
        path.addPolygon(self.tail.geometry())
        for polygon in self.handles:
            path.addEllipse(polygon.geometry())
        for polygon in self.anchors.values():
            path.addEllipse(polygon.geometry())
        return path.controlPointRect()

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        return diagram.factory.create(self.type(), **{
            'id': self.id,
            'source': self.source,
            'target': self.target,
            'breakpoints': self.breakpoints[:],
        })

    @staticmethod
    def createHead(p1, angle, size):
        """
        Create the head polygon.
        :type p1: QPointF
        :type angle: float
        :type size: int
        :rtype: QPolygonF
        """
        rad = radians(angle)
        p2 = p1 - QtCore.QPointF(sin(rad + M_PI / 3.0) * size, cos(rad + M_PI / 3.0) * size)
        p3 = p1 - QtCore.QPointF(sin(rad + M_PI - M_PI / 3.0) * size, cos(rad + M_PI - M_PI / 3.0) * size)
        return QtGui.QPolygonF([p1, p2, p3])

    @staticmethod
    def createTail(p1, angle, size):
        """
        Create the tail polygon.
        :type p1: QPointF
        :type angle: float
        :type size: int
        :rtype: QPolygonF
        """
        rad = radians(angle)
        p2 = p1 + QtCore.QPointF(sin(rad + M_PI / 3.0) * size, cos(rad + M_PI / 3.0) * size)
        p3 = p1 + QtCore.QPointF(sin(rad + M_PI - M_PI / 3.0) * size, cos(rad + M_PI - M_PI / 3.0) * size)
        return QtGui.QPolygonF([p1, p2, p3])

    def paint(self, painter, option, widget=None):
        """
        Paint the edge in the diagram scene.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.fillPath(self.selection.geometry(), self.selection.brush())
        # EDGE LINE
        painter.setPen(self.path.pen())
        painter.drawPath(self.path.geometry())
        # HEAD POLYGON
        painter.setPen(self.head.pen())
        painter.setBrush(self.head.brush())
        painter.drawPolygon(self.head.geometry())
        # TAIL POLYGON
        painter.setPen(self.tail.pen())
        painter.setBrush(self.tail.brush())
        painter.drawPolygon(self.tail.geometry())
        # BREAKPOINTS
        for polygon in self.handles:
            painter.setPen(polygon.pen())
            painter.setBrush(polygon.brush())
            painter.drawEllipse(polygon.geometry())
        # ANCHOR POINTS
        for polygon in self.anchors.values():
            painter.setPen(polygon.pen())
            painter.setBrush(polygon.brush())
            painter.drawEllipse(polygon.geometry())

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPath(self.path.geometry())
        path.addPolygon(self.head.geometry())
        path.addPolygon(self.tail.geometry())
        return path

    def setText(self, text):
        """
        Set the label text.
        :type text: str
        """
        pass

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        pass

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPath(self.selection.geometry())
        path.addPolygon(self.head.geometry())
        path.addPolygon(self.tail.geometry())
        if self.isSelected():
            for polygon in self.handles:
                path.addEllipse(polygon.geometry())
            for polygon in self.anchors.values():
                path.addEllipse(polygon.geometry())
        return path

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        pass

    def textPos(self):
        """
        Returns the current label position.
        :rtype: QPointF
        """
        pass

    def updateEdge(self, selected=None, visible=None, breakpoint=None, anchor=None, target=None, **kwargs):
        """
        Update the current edge.
        :type selected: bool
        :type visible: bool
        :type breakpoint: int
        :type anchor: AbstractNode
        :type target: QtCore.QPointF
        """
        if visible is None:
            visible = self.canDraw()

        sourceNode = self.source
        targetNode = self.target
        sourcePos = sourceNode.anchor(self)
        targetPos = target
        if targetPos is None:
            targetPos = targetNode.anchor(self)

        self.prepareGeometryChange()

        ##########################################
        # PATH, SELECTION, HEAD, TAIL (GEOMETRY)
        #################################

        collection = self.createPath(sourceNode, targetNode, [sourcePos] + self.breakpoints + [targetPos])

        selection = QtGui.QPainterPath()
        path = QtGui.QPainterPath()
        head = QtGui.QPolygonF()
        tail = QtGui.QPolygonF()

        if len(collection) == 1:
            subpath = collection[0]
            p1 = sourceNode.intersection(subpath)
            p2 = targetNode.intersection(subpath) if targetNode else subpath.p2()
            if p1 is not None and p2 is not None:
                path.moveTo(p1)
                path.lineTo(p2)
                selection.addPolygon(createArea(p1, p2, subpath.angle(), 8))
                head = self.createHead(p2, subpath.angle(), 12)
                tail = self.createTail(p1, subpath.angle(), 12)
        elif len(collection) > 1:
            subpath1 = collection[0]
            subpathN = collection[-1]
            p11 = sourceNode.intersection(subpath1)
            p22 = targetNode.intersection(subpathN)
            if p11 and p22:
                p12 = subpath1.p2()
                p21 = subpathN.p1()
                path.moveTo(p11)
                path.lineTo(p12)
                selection.addPolygon(createArea(p11, p12, subpath1.angle(), 8))
                for subpath in collection[1:-1]:
                    p1 = subpath.p1()
                    p2 = subpath.p2()
                    path.moveTo(p1)
                    path.lineTo(p2)
                    selection.addPolygon(createArea(p1, p2, subpath.angle(), 8))
                path.moveTo(p21)
                path.lineTo(p22)
                selection.addPolygon(createArea(p21, p22, subpathN.angle(), 8))
                head = self.createHead(p22, subpathN.angle(), 12)
                tail = self.createTail(p11, subpath1.angle(), 12)

        self.selection.setGeometry(selection)
        self.path.setGeometry(path)
        self.head.setGeometry(head)
        self.tail.setGeometry(tail)

        ##########################################
        # PATH, HEAD, TAIL (BRUSH)
        #################################

        headBrush = QtGui.QBrush(QtCore.Qt.NoBrush)
        headPen = QtGui.QPen(QtCore.Qt.NoPen)
        pathPen = QtGui.QPen(QtCore.Qt.NoPen)
        tailBrush = QtGui.QBrush(QtCore.Qt.NoBrush)
        tailPen = QtGui.QPen(QtCore.Qt.NoPen)

        if visible:
            headBrush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 255))
            headPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
            pathPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
            tailBrush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 255))
            tailPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)

        self.head.setBrush(headBrush)
        self.head.setPen(headPen)
        self.path.setPen(pathPen)
        self.tail.setBrush(tailBrush)
        self.tail.setPen(tailPen)

        super().updateEdge(selected, visible, breakpoint, anchor, **kwargs)
Exemple #10
0
class RoleNode(OntologyEntityResizableNode):
    """
    This class implements the 'Role' node.
    """
    IndexL = 0
    IndexB = 1
    IndexR = 2
    IndexT = 3
    IndexE = 4

    DefaultBrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                            QtCore.Qt.RoundJoin)
    Identities = {Identity.Role,Identity.Individual}
    Type = Item.RoleIRINode

    def __init__(self, iri = None, width=70, height=50, brush=None, **kwargs):
        """
        Initialize the node.
        :type width: int
        :type height: int
        :type brush: QBrush
        """
        super().__init__(iri=iri,**kwargs)

        w = max(width, 70)
        h = max(height, 50)
        brush = brush or RoleNode.DefaultBrush
        pen = RoleNode.DefaultPen

        createPolygon = lambda x, y: QtGui.QPolygonF([
            QtCore.QPointF(-x / 2, 0),
            QtCore.QPointF(0, +y / 2),
            QtCore.QPointF(+x / 2, 0),
            QtCore.QPointF(0, -y / 2),
            QtCore.QPointF(-x / 2, 0)
        ])

        self.fpolygon = Polygon(QtGui.QPainterPath())
        self.ipolygon = Polygon(QtGui.QPainterPath())
        self.background = Polygon(createPolygon(w + 8, h + 8))
        self.selection = Polygon(createPolygon(w + 8, h + 8))
        self.polygon = Polygon(createPolygon(w, h), brush, pen)

        self.updateNode()

    def connectIRIMetaSignals(self):
        connect(self.iri.sgnFunctionalModified,self.onFunctionalModified)
        connect(self.iri.sgnInverseFunctionalModified, self.onFunctionalModified)

    def disconnectIRIMetaSignals(self):
        disconnect(self.iri.sgnFunctionalModified,self.onFunctionalModified)
        disconnect(self.iri.sgnInverseFunctionalModified, self.onFunctionalModified)

    @QtCore.pyqtSlot()
    def onFunctionalModified(self):
        self.updateNode()

    #############################################
    #   INTERFACE
    #################################
    def initialLabelPosition(self):
        return self.center() - QtCore.QPointF(0, 30)

    def occursAsIndividual(self):
        #Class Assertion
        for instEdge in [x for x in self.edges if x.type() is Item.MembershipEdge]:
            if instEdge.source is self:
                return True
        #Object[Data] Property Assertion
        for inputEdge in [x for x in self.edges if x.type() is Item.InputEdge]:
            if inputEdge.source is self and inputEdge.target.type() is Item.PropertyAssertionNode:
                return True
        #SameAs and Different
        for inputEdge in [x for x in self.edges if (x.type() is Item.SameEdge or x.type() is Item.DifferentEdge)]:
            if inputEdge.source is self or inputEdge.target is self:
                return True
        return False

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QtCore.QRectF
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.selection.geometry())
        return path.boundingRect()

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        node = diagram.factory.create(self.type(), **{
            'id': self.id,
            'brush': self.brush(),
            'height': self.height(),
            'width': self.width(),
            'iri': None,
        })
        node.setPos(self.pos())
        node.iri = self.iri
        node.setTextPos(node.mapFromScene(self.mapToScene(self.textPos())))
        return node

    def definition(self):
        """
        Returns the list of nodes which contribute to the definition of this very node.
        :rtype: set
        """
        f1 = lambda x: x.type() is Item.InputEdge
        f2 = lambda x: x.type() in {Item.DomainRestrictionNode, Item.RangeRestrictionNode}
        return self.outgoingNodes(filter_on_edges=f1, filter_on_nodes=f2)

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        polygon = self.polygon.geometry()
        return polygon[self.IndexB].y() - polygon[self.IndexT].y()

    def identity(self):
        """
        Returns the identity of the current node.
        :rtype: Identity
        """
        return Identity.Role

    def isAsymmetric(self):
        """
        Returns True if the predicate represented by this node is asymmetric, False otherwise.
        :rtype: bool
        """
        return self.iri.asymmetric

    def isFunctional(self):
        """
        Returns True if the predicate represented by this node is functional, else False.
        :rtype: bool
        """
        return self.iri.functional

    def isInverseFunctional(self):
        """
        Returns True if the predicate represented by this node is inverse functional, else False.
        :rtype: bool
        """
        return self.iri.inverseFunctional

    def isIrreflexive(self):
        """
        Returns True if the predicate represented by this node is irreflexive, False otherwise.
        :rtype: bool
        """
        return self.iri.irreflexive

    def isReflexive(self):
        """
        Returns True if the predicate represented by this node is reflexive, False otherwise.
        :rtype: bool
        """
        return self.iri.reflexive

    def isSymmetric(self):
        """
        Returns True if the predicate represented by this node is symmetric, False otherwise.
        :rtype: bool
        """
        return self.iri.symmetric

    def isTransitive(self):
        """
        Returns True if the transitive represented by this node is symmetric, False otherwise.
        :rtype: bool
        """
        return self.iri.transitive

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawPolygon(self.selection.geometry())
        # SYNTAX VALIDATION
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawPolygon(self.background.geometry())
        # ITEM SHAPE
        painter.setPen(self.polygon.pen())
        painter.setBrush(self.polygon.brush())
        painter.drawPolygon(self.polygon.geometry())
        # FUNCTIONALITY
        painter.setPen(self.fpolygon.pen())
        painter.setBrush(self.fpolygon.brush())
        painter.drawPath(self.fpolygon.geometry())
        # INVERSE FUNCTIONALITY
        painter.setPen(self.ipolygon.pen())
        painter.setBrush(self.ipolygon.brush())
        painter.drawPath(self.ipolygon.geometry())
        # RESIZE HANDLES
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        for polygon in self.handles:
            painter.setPen(polygon.pen())
            painter.setBrush(polygon.brush())
            painter.drawEllipse(polygon.geometry())

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        return path

    def resize(self, mousePos):
        """
        Handle the interactive resize of the shape.
        :type mousePos: QtCore.QPointF
        """
        snap = self.session.action('toggle_grid').isChecked()
        size = self.diagram.GridSize
        moved = self.label.isMoved()

        background = self.background.geometry()
        selection = self.selection.geometry()
        polygon = self.polygon.geometry()

        R = QtCore.QRectF(self.boundingRect())
        D = QtCore.QPointF(0, 0)

        mbrh = 58
        mbrw = 78

        self.prepareGeometryChange()

        if self.mp_Handle == self.HandleTL:

            fromX = self.mp_Bound.left()
            fromY = self.mp_Bound.top()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, -4, snap)
            toY = snapF(toY, size, -4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            selection[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2, R.top())
            selection[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2, selection[self.IndexB].y())
            selection[self.IndexL] = QtCore.QPointF(R.left(), R.top() + R.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(R.left(), R.top() + R.height() / 2)
            selection[self.IndexR] = QtCore.QPointF(selection[self.IndexR].x(), R.top() + R.height() / 2)

            background[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2, R.top())
            background[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2, background[self.IndexB].y())
            background[self.IndexL] = QtCore.QPointF(R.left(), R.top() + R.height() / 2)
            background[self.IndexE] = QtCore.QPointF(R.left(), R.top() + R.height() / 2)
            background[self.IndexR] = QtCore.QPointF(background[self.IndexR].x(), R.top() + R.height() / 2)

            polygon[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2, R.top() + 4)
            polygon[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2, polygon[self.IndexB].y())
            polygon[self.IndexL] = QtCore.QPointF(R.left() + 4, R.top() + R.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(R.left() + 4, R.top() + R.height() / 2)
            polygon[self.IndexR] = QtCore.QPointF(polygon[self.IndexR].x(), R.top() + R.height() / 2)

        elif self.mp_Handle == self.HandleTM:

            fromY = self.mp_Bound.top()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toY = snapF(toY, size, -4, snap)
            D.setY(toY - fromY)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            selection[self.IndexT] = QtCore.QPointF(selection[self.IndexT].x(), R.top())
            selection[self.IndexL] = QtCore.QPointF(selection[self.IndexL].x(), R.top() + R.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(selection[self.IndexE].x(), R.top() + R.height() / 2)
            selection[self.IndexR] = QtCore.QPointF(selection[self.IndexR].x(), R.top() + R.height() / 2)

            background[self.IndexT] = QtCore.QPointF(background[self.IndexT].x(), R.top())
            background[self.IndexL] = QtCore.QPointF(background[self.IndexL].x(), R.top() + R.height() / 2)
            background[self.IndexE] = QtCore.QPointF(background[self.IndexE].x(), R.top() + R.height() / 2)
            background[self.IndexR] = QtCore.QPointF(background[self.IndexR].x(), R.top() + R.height() / 2)

            polygon[self.IndexT] = QtCore.QPointF(polygon[self.IndexT].x(), R.top() + 4)
            polygon[self.IndexL] = QtCore.QPointF(polygon[self.IndexL].x(), R.top() + R.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(polygon[self.IndexE].x(), R.top() + R.height() / 2)
            polygon[self.IndexR] = QtCore.QPointF(polygon[self.IndexR].x(), R.top() + R.height() / 2)

        elif self.mp_Handle == self.HandleTR:

            fromX = self.mp_Bound.right()
            fromY = self.mp_Bound.top()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, +4, snap)
            toY = snapF(toY, size, -4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            selection[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2, R.top())
            selection[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2, selection[self.IndexB].y())
            selection[self.IndexL] = QtCore.QPointF(selection[self.IndexL].x(), R.top() + R.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(selection[self.IndexE].x(), R.top() + R.height() / 2)
            selection[self.IndexR] = QtCore.QPointF(R.right(), R.top() + R.height() / 2)

            background[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2, R.top())
            background[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2, background[self.IndexB].y())
            background[self.IndexL] = QtCore.QPointF(background[self.IndexL].x(), R.top() + R.height() / 2)
            background[self.IndexE] = QtCore.QPointF(background[self.IndexE].x(), R.top() + R.height() / 2)
            background[self.IndexR] = QtCore.QPointF(R.right(), R.top() + R.height() / 2)

            polygon[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2, R.top() + 4)
            polygon[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2, polygon[self.IndexB].y())
            polygon[self.IndexL] = QtCore.QPointF(polygon[self.IndexL].x(), R.top() + R.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(polygon[self.IndexE].x(), R.top() + R.height() / 2)
            polygon[self.IndexR] = QtCore.QPointF(R.right() - 4, R.top() + R.height() / 2)

        elif self.mp_Handle == self.HandleML:

            fromX = self.mp_Bound.left()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toX = snapF(toX, size, -4, snap)
            D.setX(toX - fromX)
            R.setLeft(toX)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())

            selection[self.IndexL] = QtCore.QPointF(R.left(), self.mp_Bound.top() + self.mp_Bound.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(R.left(), self.mp_Bound.top() + self.mp_Bound.height() / 2)
            selection[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2, selection[self.IndexT].y())
            selection[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2, selection[self.IndexB].y())

            background[self.IndexL] = QtCore.QPointF(R.left(), self.mp_Bound.top() + self.mp_Bound.height() / 2)
            background[self.IndexE] = QtCore.QPointF(R.left(), self.mp_Bound.top() + self.mp_Bound.height() / 2)
            background[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2, background[self.IndexT].y())
            background[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2, background[self.IndexB].y())

            polygon[self.IndexL] = QtCore.QPointF(R.left() + 4, self.mp_Bound.top() + self.mp_Bound.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(R.left() + 4, self.mp_Bound.top() + self.mp_Bound.height() / 2)
            polygon[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2, polygon[self.IndexT].y())
            polygon[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2, polygon[self.IndexB].y())

        elif self.mp_Handle == self.HandleMR:

            fromX = self.mp_Bound.right()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toX = snapF(toX, size, +4, snap)
            D.setX(toX - fromX)
            R.setRight(toX)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())

            selection[self.IndexR] = QtCore.QPointF(R.right(), self.mp_Bound.top() + self.mp_Bound.height() / 2)
            selection[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2, selection[self.IndexT].y())
            selection[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2, selection[self.IndexB].y())

            background[self.IndexR] = QtCore.QPointF(R.right(), self.mp_Bound.top() + self.mp_Bound.height() / 2)
            background[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2, background[self.IndexT].y())
            background[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2, background[self.IndexB].y())

            polygon[self.IndexR] = QtCore.QPointF(R.right() - 4, self.mp_Bound.top() + self.mp_Bound.height() / 2)
            polygon[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2, polygon[self.IndexT].y())
            polygon[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2, polygon[self.IndexB].y())

        elif self.mp_Handle == self.HandleBL:

            fromX = self.mp_Bound.left()
            fromY = self.mp_Bound.bottom()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, -4, snap)
            toY = snapF(toY, size, +4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            selection[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2, selection[self.IndexT].y())
            selection[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2, R.bottom())
            selection[self.IndexL] = QtCore.QPointF(R.left(), R.bottom() - R.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(R.left(), R.bottom() - R.height() / 2)
            selection[self.IndexR] = QtCore.QPointF(selection[self.IndexR].x(), R.bottom() - R.height() / 2)

            background[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2, background[self.IndexT].y())
            background[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2, R.bottom())
            background[self.IndexL] = QtCore.QPointF(R.left(), R.bottom() - R.height() / 2)
            background[self.IndexE] = QtCore.QPointF(R.left(), R.bottom() - R.height() / 2)
            background[self.IndexR] = QtCore.QPointF(background[self.IndexR].x(), R.bottom() - R.height() / 2)

            polygon[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2, polygon[self.IndexT].y())
            polygon[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2, R.bottom() - 4)
            polygon[self.IndexL] = QtCore.QPointF(R.left() + 4, R.bottom() - R.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(R.left() + 4, R.bottom() - R.height() / 2)
            polygon[self.IndexR] = QtCore.QPointF(polygon[self.IndexR].x(), R.bottom() - R.height() / 2)

        elif self.mp_Handle == self.HandleBM:

            fromY = self.mp_Bound.bottom()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toY = snapF(toY, size, +4, snap)
            D.setY(toY - fromY)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            selection[self.IndexB] = QtCore.QPointF(selection[self.IndexB].x(), R.bottom())
            selection[self.IndexL] = QtCore.QPointF(selection[self.IndexL].x(), R.top() + R.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(selection[self.IndexE].x(), R.top() + R.height() / 2)
            selection[self.IndexR] = QtCore.QPointF(selection[self.IndexR].x(), R.top() + R.height() / 2)

            background[self.IndexB] = QtCore.QPointF(background[self.IndexB].x(), R.bottom())
            background[self.IndexL] = QtCore.QPointF(background[self.IndexL].x(), R.top() + R.height() / 2)
            background[self.IndexE] = QtCore.QPointF(background[self.IndexE].x(), R.top() + R.height() / 2)
            background[self.IndexR] = QtCore.QPointF(background[self.IndexR].x(), R.top() + R.height() / 2)

            polygon[self.IndexB] = QtCore.QPointF(polygon[self.IndexB].x(), R.bottom() - 4)
            polygon[self.IndexL] = QtCore.QPointF(polygon[self.IndexL].x(), R.top() + R.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(polygon[self.IndexE].x(), R.top() + R.height() / 2)
            polygon[self.IndexR] = QtCore.QPointF(polygon[self.IndexR].x(), R.top() + R.height() / 2)

        elif self.mp_Handle == self.HandleBR:

            fromX = self.mp_Bound.right()
            fromY = self.mp_Bound.bottom()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, +4, snap)
            toY = snapF(toY, size, +4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            selection[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2, selection[self.IndexT].y())
            selection[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2, R.bottom())
            selection[self.IndexL] = QtCore.QPointF(selection[self.IndexL].x(), R.bottom() - R.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(selection[self.IndexE].x(), R.bottom() - R.height() / 2)
            selection[self.IndexR] = QtCore.QPointF(R.right(), R.bottom() - R.height() / 2)

            background[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2, background[self.IndexT].y())
            background[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2, R.bottom())
            background[self.IndexL] = QtCore.QPointF(background[self.IndexL].x(), R.bottom() - R.height() / 2)
            background[self.IndexE] = QtCore.QPointF(background[self.IndexE].x(), R.bottom() - R.height() / 2)
            background[self.IndexR] = QtCore.QPointF(R.right(), R.bottom() - R.height() / 2)

            polygon[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2, polygon[self.IndexT].y())
            polygon[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2, R.bottom() - 4)
            polygon[self.IndexL] = QtCore.QPointF(polygon[self.IndexL].x(), R.bottom() - R.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(polygon[self.IndexE].x(), R.bottom() - R.height() / 2)
            polygon[self.IndexR] = QtCore.QPointF(R.right() - 4, R.bottom() - R.height() / 2)

        self.background.setGeometry(background)
        self.selection.setGeometry(selection)
        self.polygon.setGeometry(polygon)

        self.updateNode(selected=True, handle=self.mp_Handle, anchors=(self.mp_Data, D))
        self.updateTextPos(moved=moved)

    def setAsymmetric(self, asymmetric):
        """
        Set the asymmetric property for the predicate represented by this node.
        :type asymmetric: bool
        """
        self.iri.asymmetric = asymmetric

    def setFunctional(self, functional):
        """
        Set the functional property of the predicate represented by this node.
        :type functional: bool
        """
        self.iri.functional = functional

    def setIdentity(self, identity):
        """
        Set the identity of the current node.
        :type identity: Identity
        """
        pass

    def setInverseFunctional(self, inverseFunctional):
        """
        Set the inverse functional property of the predicate represented by this node.
        :type inverseFunctional: bool
        """
        self.iri.inverseFunctional = inverseFunctional

    def setIrreflexive(self, irreflexive):
        """
        Set the irreflexive property for the predicate represented by this node.
        :type irreflexive: bool
        """
        self.iri.irreflexive = irreflexive

    def setReflexive(self, reflexive):
        """
        Set the reflexive property for the predicate represented by this node.
        :type reflexive: bool
        """
        self.iri.reflexive = reflexive

    def setSymmetric(self, symmetric):
        """
        Set the symmetric property for the predicate represented by this node.
        :type symmetric: bool
        """
        self.iri.symmetric = symmetric

    def setTransitive(self, transitive):
        """
        Set the transitive property for the predicate represented by this node.
        :type transitive: bool
        """
        self.iri.transitive = transitive

    def setText(self, text):
        """
        Set the label text.
        :type text: str
        """
        self.label.setText(text)

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        self.label.setPos(pos)
        self.label.setAlignment(QtCore.Qt.AlignCenter)

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        for polygon in self.handles:
            path.addEllipse(polygon.geometry())
        return path

    def special(self):
        """
        Returns the special type of this node.
        :rtype: Special
        """
        # TODO implementa nuova versione passando da metodo IRI.isTopBottomEntity (isOWlThing? etc etc...)
        return Special.valueOf(self.text())

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        return self.label.text()

    def textPos(self):
        """
        Returns the current label position in item coordinates.
        :rtype: QPointF
        """
        return self.label.pos()

    def updateNode(self, functional=None, inverseFunctional=None, **kwargs):
        """
        Update the current node.
        :type functional: bool
        :type inverseFunctional: bool
        """
        if functional is None:
            if self.iri:
                functional = self.isFunctional()
                #TODO CANCELLA
                if functional is None:
                    functional = False
                # TODO END CANCELLA
        if inverseFunctional is None:
            if self.iri:
                inverseFunctional = self.isInverseFunctional()
                # TODO CANCELLA
                if inverseFunctional is None:
                    inverseFunctional = False
                # TODO END CANCELLA

        polygon = self.polygon.geometry()

        # FUNCTIONAL POLYGON (SHAPE)
        fpolygon = QtGui.QPainterPath()
        if functional and not inverseFunctional:
            path = QtGui.QPainterPath()
            path.addPolygon(QtGui.QPolygonF([
                polygon[self.IndexL] + QtCore.QPointF(+5, 0),
                polygon[self.IndexB] + QtCore.QPointF(0, -4),
                polygon[self.IndexR] + QtCore.QPointF(-5, 0),
                polygon[self.IndexT] + QtCore.QPointF(0, +4),
                polygon[self.IndexL] + QtCore.QPointF(+5, 0),
            ]))
            fpolygon.addPolygon(polygon)
            fpolygon = fpolygon.subtracted(path)

        # INVERSE FUNCTIONAL POLYGON (SHAPE)
        ipolygon = QtGui.QPainterPath()
        if not functional and inverseFunctional:
            path = QtGui.QPainterPath()
            path.addPolygon(QtGui.QPolygonF([
                polygon[self.IndexL] + QtCore.QPointF(+5, 0),
                polygon[self.IndexB] + QtCore.QPointF(0, -4),
                polygon[self.IndexR] + QtCore.QPointF(-5, 0),
                polygon[self.IndexT] + QtCore.QPointF(0, +4),
                polygon[self.IndexL] + QtCore.QPointF(+5, 0),
            ]))
            ipolygon.addPolygon(polygon)
            ipolygon = ipolygon.subtracted(path)

        # FUNCTIONAL + INVERSE FUNCTIONAL POLYGONS (SHAPE)
        if functional and inverseFunctional:
            path = QtGui.QPainterPath()
            path.addPolygon(QtGui.QPolygonF([
                polygon[self.IndexL] + QtCore.QPointF(+5, 0),
                polygon[self.IndexB] + QtCore.QPointF(0, -4),
                polygon[self.IndexB],
                polygon[self.IndexR],
                polygon[self.IndexT],
                polygon[self.IndexT] + QtCore.QPointF(0, +4),
                polygon[self.IndexL] + QtCore.QPointF(+5, 0),
            ]))
            fpolygon.addPolygon(polygon)
            fpolygon = fpolygon.subtracted(path)
            path = QtGui.QPainterPath()
            path.addPolygon(QtGui.QPolygonF([
                polygon[self.IndexL],
                polygon[self.IndexB],
                polygon[self.IndexB] + QtCore.QPointF(0, -4),
                polygon[self.IndexR] + QtCore.QPointF(-5, 0),
                polygon[self.IndexT] + QtCore.QPointF(0, +4),
                polygon[self.IndexT],
                polygon[self.IndexL],
            ]))
            ipolygon.addPolygon(polygon)
            ipolygon = ipolygon.subtracted(path)

        # FUNCTIONAL POLYGON (PEN + BRUSH)
        fpen = QtGui.QPen(QtCore.Qt.NoPen)
        fbrush = QtGui.QBrush(QtCore.Qt.NoBrush)
        if functional:
            fpen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                              QtCore.Qt.RoundJoin)
            fbrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))

        # INVERSE FUNCTIONAL POLYGON (PEN + BRUSH)
        ipen = QtGui.QPen(QtCore.Qt.NoPen)
        ibrush = QtGui.QBrush(QtCore.Qt.NoBrush)
        if inverseFunctional:
            ipen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                              QtCore.Qt.RoundJoin)
            ibrush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 255))

        self.fpolygon.setPen(fpen)
        self.fpolygon.setBrush(fbrush)
        self.fpolygon.setGeometry(fpolygon)
        self.ipolygon.setPen(ipen)
        self.ipolygon.setBrush(ibrush)
        self.ipolygon.setGeometry(ipolygon)

        # SELECTION + BACKGROUND + HANDLES + ANCHORS + CACHE REFRESH
        super().updateNode(**kwargs)

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        self.label.updatePos(*args, **kwargs)

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        polygon = self.polygon.geometry()
        return polygon[self.IndexR].x() - polygon[self.IndexL].x()

    def __repr__(self):
        """
        Returns repr(self).
        """
        return '{0}:{1}:{2}'.format(self.__class__.__name__, self.text(), self.id)# -*- coding: utf-8 -*-
class ValueDomainNode(AbstractNode):
    """
    This class implements the 'Value-Domain' node.
    """
    DefaultBrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.0, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
    Identities = {Identity.ValueDomain}
    Type = Item.ValueDomainNode

    def __init__(self, width=90, height=40, brush=None, **kwargs):
        """
        Initialize the ValueDomain node.
        :type width: int
        :type height: int
        :type brush: QBrush
        """
        super().__init__(**kwargs)
        brush = brush or ValueDomainNode.DefaultBrush
        pen = ValueDomainNode.DefaultPen
        self.background = Polygon(QtCore.QRectF(-49, -24, 98, 48))
        self.selection = Polygon(QtCore.QRectF(-49, -24, 98, 48))
        self.polygon = Polygon(QtCore.QRectF(-45, -20, 90, 40), brush, pen)
        self.label = NodeLabel(Datatype.string.value, pos=self.center, editable=False, movable=False, parent=self)
        self.updateNode()
        self.updateTextPos()

    #############################################
    #   PROPERTIES
    #################################

    @property
    def datatype(self):
        """
        Returns the datatype associated with this node.
        :rtype: Datatype
        """
        return Datatype.forValue(self.text())

    #############################################
    #   INTERFACE
    #################################

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QtCore.QRectF
        """
        return self.selection.geometry()

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        node = diagram.factory.create(self.type(), **{
            'id': self.id,
            'brush': self.brush(),
            'height': self.height(),
            'width': self.width()
        })
        node.setPos(self.pos())
        node.setText(self.text())
        node.setTextPos(node.mapFromScene(self.mapToScene(self.textPos())))
        return node

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        return self.polygon.geometry().height()

    def identity(self):
        """
        Returns the identity of the current node.
        :rtype: Identity
        """
        return Identity.ValueDomain

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawRoundedRect(self.selection.geometry(), 8, 8)
        # SYNTAX VALIDATION
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawRoundedRect(self.background.geometry(), 8, 8)
        # SHAPE
        painter.setPen(self.polygon.pen())
        painter.setBrush(self.polygon.brush())
        painter.drawRoundedRect(self.polygon.geometry(), 8, 8)

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addRoundedRect(self.polygon.geometry(), 8, 8)
        return path

    def setIdentity(self, identity):
        """
        Set the identity of the current node.
        :type identity: Identity
        """
        pass

    def setText(self, text):
        """
        Set the label text.
        :type text: str
        """
        datatype = Datatype.forValue(text) or Datatype.string
        self.label.setText(datatype.value)
        self.updateNode()

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        self.label.setPos(pos)

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addRoundedRect(self.polygon.geometry(), 8, 8)
        return path

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        return self.label.text()

    def textPos(self):
        """
        Returns the current label position in item coordinates.
        :rtype: QPointF
        """
        return self.label.pos()

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        self.label.updatePos(*args, **kwargs)

    def updateNode(self, *args, **kwargs):
        """
        Update the current node.
        """
        # POLYGON + BACKGROUND + SELECTION (GEOMETRY)
        width = max(self.label.width() + 16, 90)
        self.polygon.setGeometry(QtCore.QRectF(-width / 2, -20, width, 40))
        self.background.setGeometry(QtCore.QRectF(-(width + 8) / 2, -24, width + 8, 48))
        self.selection.setGeometry(QtCore.QRectF(-(width + 8) / 2, -24, width + 8, 48))
        self.updateTextPos()
        self.updateEdges()

        # SELECTION + BACKGROUND + CACHE REFRESH
        super().updateNode(**kwargs)

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        return self.polygon.geometry().width()

    def __repr__(self):
        """
        Returns repr(self).
        """
        return '{0}:{1}:{2}'.format(self.__class__.__name__, self.text(), self.id)
Exemple #12
0
class AttributeNode(AbstractNode):
    """
    This class implements the 'Attribute' node.
    """
    DefaultBrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
    Identities = {Identity.Attribute}
    Type = Item.AttributeNode

    def __init__(self, width=20, height=20, brush=None, **kwargs):
        """
        Initialize the node.
        :type width: int
        :type height: int
        :type brush: QBrush
        """
        super().__init__(**kwargs)
        brush = brush or AttributeNode.DefaultBrush
        pen = AttributeNode.DefaultPen
        self.fpolygon = Polygon(QtGui.QPainterPath())
        self.background = Polygon(QtCore.QRectF(-14, -14, 28, 28))
        self.selection = Polygon(QtCore.QRectF(-14, -14, 28, 28))
        self.polygon = Polygon(QtCore.QRectF(-10, -10, 20, 20), brush, pen)
        self.label = NodeLabel(template='attribute', pos=lambda: self.center() - QtCore.QPointF(0, 22), parent=self)
        self.label.setAlignment(QtCore.Qt.AlignCenter)

    #############################################
    #   INTERFACE
    #################################

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QRectF
        """
        return self.selection.geometry()

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        node = diagram.factory.create(self.type(), **{
            'id': self.id,
            'brush': self.brush(),
            'height': self.height(),
            'width': self.width()
        })
        node.setPos(self.pos())
        node.setText(self.text())
        node.setTextPos(node.mapFromScene(self.mapToScene(self.textPos())))
        return node

    def definition(self):
        """
        Returns the list of nodes which contribute to the definition of this very node.
        :rtype: set
        """
        f1 = lambda x: x.type() is Item.InputEdge
        f2 = lambda x: x.type() in {Item.DomainRestrictionNode, Item.RangeRestrictionNode}
        return set(self.outgoingNodes(filter_on_edges=f1, filter_on_nodes=f2))

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        return self.polygon.geometry().height()

    def identity(self):
        """
        Returns the identity of the current node.
        :rtype: Identity
        """
        return Identity.Attribute

    def isFunctional(self):
        """
        Returns True if the predicate represented by this node is functional, else False.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(), self.text())['functional'] and \
                   self.project.profile.type() is not OWLProfile.OWL2QL
        except (AttributeError, KeyError):
            return False

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawEllipse(self.selection.geometry())
        # SYNTAX VALIDATION
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawEllipse(self.background.geometry())
        # ITEM SHAPE
        painter.setPen(self.polygon.pen())
        painter.setBrush(self.polygon.brush())
        painter.drawEllipse(self.polygon.geometry())
        # FUNCTIONALITY
        painter.setPen(self.fpolygon.pen())
        painter.setBrush(self.fpolygon.brush())
        painter.drawPath(self.fpolygon.geometry())

    def painterPath(self):
        """
        Returns the current shape as QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addEllipse(self.polygon.geometry())
        return path

    def setFunctional(self, functional):
        """
        Set the functional property of the predicate represented by this node.
        :type functional: bool
        """
        meta = self.project.meta(self.type(), self.text())
        meta['functional'] = bool(functional)
        self.project.setMeta(self.type(), self.text(), meta)
        for node in self.project.predicates(self.type(), self.text()):
            node.updateNode(functional=functional, selected=node.isSelected())

    def setIdentity(self, identity):
        """
        Set the identity of the current node.
        :type identity: Identity
        """
        pass

    def setText(self, text):
        """
        Set the label text.
        :type text: str
        """
        self.label.setText(text)
        self.label.setAlignment(QtCore.Qt.AlignCenter)

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        self.label.setPos(pos)

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addEllipse(self.polygon.geometry())
        return path

    def special(self):
        """
        Returns the special type of this node.
        :rtype: Special
        """
        return Special.forValue(self.text())

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        return self.label.text()

    def textPos(self):
        """
        Returns the current label position in item coordinates.
        :rtype: QPointF
        """
        return self.label.pos()

    def updateNode(self, functional=None, **kwargs):
        """
        Update the current node.
        :type functional: bool
        """
        if functional is None:
            functional = self.isFunctional()

        # FUNCTIONAL POLYGON (SHAPE)
        path1 = QtGui.QPainterPath()
        path1.addEllipse(self.polygon.geometry())
        path2 = QtGui.QPainterPath()
        path2.addEllipse(QtCore.QRectF(-7, -7, 14, 14))
        self.fpolygon.setGeometry(path1.subtracted(path2))

        # FUNCTIONAL POLYGON (PEN & BRUSH)
        pen = QtGui.QPen(QtCore.Qt.NoPen)
        brush = QtGui.QBrush(QtCore.Qt.NoBrush)
        if functional:
            pen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
            brush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
        self.fpolygon.setPen(pen)
        self.fpolygon.setBrush(brush)

        # SELECTION + BACKGROUND + CACHE REFRESH
        super().updateNode(**kwargs)

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        self.label.updatePos(*args, **kwargs)

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        return self.polygon.geometry().width()

    def __repr__(self):
        """
        Returns repr(self).
        """
        return '{0}:{1}:{2}'.format(self.__class__.__name__, self.text(), self.id)
Exemple #13
0
class RoleNode(AbstractResizableNode):
    """
    This class implements the 'Role' node.
    """
    IndexL = 0
    IndexB = 1
    IndexR = 2
    IndexT = 3
    IndexE = 4

    DefaultBrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
    Identities = {Identity.Role}
    Type = Item.RoleNode

    def __init__(self, width=70, height=50, brush=None, **kwargs):
        """
        Initialize the node.
        :type width: int
        :type height: int
        :type brush: QBrush
        """
        super().__init__(**kwargs)
        
        w = max(width, 70)
        h = max(height, 50)
        brush = brush or RoleNode.DefaultBrush
        pen = RoleNode.DefaultPen

        createPolygon = lambda x, y: QtGui.QPolygonF([
            QtCore.QPointF(-x / 2, 0),
            QtCore.QPointF(0, +y / 2),
            QtCore.QPointF(+x / 2, 0),
            QtCore.QPointF(0, -y / 2),
            QtCore.QPointF(-x / 2, 0)
        ])

        self.fpolygon = Polygon(QtGui.QPainterPath())
        self.ipolygon = Polygon(QtGui.QPainterPath())
        self.background = Polygon(createPolygon(w + 8, h + 8))
        self.selection = Polygon(createPolygon(w + 8, h + 8))
        self.polygon = Polygon(createPolygon(w, h), brush, pen)
        self.label = NodeLabel(template='role', pos=self.center, parent=self)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.updateNode()
        self.updateTextPos()

    #############################################
    #   INTERFACE
    #################################

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QtCore.QRectF
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.selection.geometry())
        return path.boundingRect()

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        node = diagram.factory.create(self.type(), **{
            'id': self.id,
            'brush': self.brush(),
            'height': self.height(),
            'width': self.width()
        })
        node.setPos(self.pos())
        node.setText(self.text())
        node.setTextPos(node.mapFromScene(self.mapToScene(self.textPos())))
        return node

    def definition(self):
        """
        Returns the list of nodes which contribute to the definition of this very node.
        :rtype: set
        """
        f1 = lambda x: x.type() is Item.InputEdge
        f2 = lambda x: x.type() in {Item.DomainRestrictionNode, Item.RangeRestrictionNode}
        return self.outgoingNodes(filter_on_edges=f1, filter_on_nodes=f2)

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        polygon = self.polygon.geometry()
        return polygon[self.IndexB].y() - polygon[self.IndexT].y()

    def identity(self):
        """
        Returns the identity of the current node.
        :rtype: Identity
        """
        return Identity.Role

    def isAsymmetric(self):
        """
        Returns True if the predicate represented by this node is asymmetric, False otherwise.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(), self.text())['asymmetric']
        except (AttributeError, KeyError):
            return False

    def isFunctional(self):
        """
        Returns True if the predicate represented by this node is functional, else False.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(), self.text())['functional'] and \
                   self.project.profile.type() is not OWLProfile.OWL2QL
        except (AttributeError, KeyError):
            return False

    def isInverseFunctional(self):
        """
        Returns True if the predicate represented by this node is inverse functional, else False.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(), self.text())['inverseFunctional'] and \
                   self.project.profile.type() is not OWLProfile.OWL2QL
        except (AttributeError, KeyError):
            return False

    def isIrreflexive(self):
        """
        Returns True if the predicate represented by this node is irreflexive, False otherwise.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(), self.text())['irreflexive']
        except (AttributeError, KeyError):
            return False

    def isReflexive(self):
        """
        Returns True if the predicate represented by this node is reflexive, False otherwise.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(), self.text())['reflexive'] and \
                   self.project.profile.type() is not OWLProfile.OWL2RL
        except (AttributeError, KeyError):
            return False

    def isSymmetric(self):
        """
        Returns True if the predicate represented by this node is symmetric, False otherwise.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(), self.text())['symmetric']
        except (AttributeError, KeyError):
            return False

    def isTransitive(self):
        """
        Returns True if the transitive represented by this node is symmetric, False otherwise.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(), self.text())['transitive'] and \
                   self.project.profile.type() is not OWLProfile.OWL2QL
        except (AttributeError, KeyError):
            return False

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawPolygon(self.selection.geometry())
        # SYNTAX VALIDATION
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawPolygon(self.background.geometry())
        # ITEM SHAPE
        painter.setPen(self.polygon.pen())
        painter.setBrush(self.polygon.brush())
        painter.drawPolygon(self.polygon.geometry())
        # FUNCTIONALITY
        painter.setPen(self.fpolygon.pen())
        painter.setBrush(self.fpolygon.brush())
        painter.drawPath(self.fpolygon.geometry())
        # INVERSE FUNCTIONALITY
        painter.setPen(self.ipolygon.pen())
        painter.setBrush(self.ipolygon.brush())
        painter.drawPath(self.ipolygon.geometry())
        # RESIZE HANDLES
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        for polygon in self.handles:
            painter.setPen(polygon.pen())
            painter.setBrush(polygon.brush())
            painter.drawEllipse(polygon.geometry())

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        return path

    def resize(self, mousePos):
        """
        Handle the interactive resize of the shape.
        :type mousePos: QtCore.QPointF
        """
        snap = self.session.action('toggle_grid').isChecked()
        size = self.diagram.GridSize
        moved = self.label.isMoved()

        background = self.background.geometry()
        selection = self.selection.geometry()
        polygon = self.polygon.geometry()
        
        R = QtCore.QRectF(self.boundingRect())
        D = QtCore.QPointF(0, 0)

        mbrh = 58
        mbrw = 78

        self.prepareGeometryChange()

        if self.mp_Handle == self.HandleTL:

            fromX = self.mp_Bound.left()
            fromY = self.mp_Bound.top()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, -4, snap)
            toY = snapF(toY, size, -4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            selection[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2, R.top())
            selection[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2, selection[self.IndexB].y())
            selection[self.IndexL] = QtCore.QPointF(R.left(), R.top() + R.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(R.left(), R.top() + R.height() / 2)
            selection[self.IndexR] = QtCore.QPointF(selection[self.IndexR].x(), R.top() + R.height() / 2)

            background[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2, R.top())
            background[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2, background[self.IndexB].y())
            background[self.IndexL] = QtCore.QPointF(R.left(), R.top() + R.height() / 2)
            background[self.IndexE] = QtCore.QPointF(R.left(), R.top() + R.height() / 2)
            background[self.IndexR] = QtCore.QPointF(background[self.IndexR].x(), R.top() + R.height() / 2)
            
            polygon[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2, R.top() + 4)
            polygon[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2, polygon[self.IndexB].y())
            polygon[self.IndexL] = QtCore.QPointF(R.left() + 4, R.top() + R.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(R.left() + 4, R.top() + R.height() / 2)
            polygon[self.IndexR] = QtCore.QPointF(polygon[self.IndexR].x(), R.top() + R.height() / 2)

        elif self.mp_Handle == self.HandleTM:

            fromY = self.mp_Bound.top()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toY = snapF(toY, size, -4, snap)
            D.setY(toY - fromY)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            selection[self.IndexT] = QtCore.QPointF(selection[self.IndexT].x(), R.top())
            selection[self.IndexL] = QtCore.QPointF(selection[self.IndexL].x(), R.top() + R.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(selection[self.IndexE].x(), R.top() + R.height() / 2)
            selection[self.IndexR] = QtCore.QPointF(selection[self.IndexR].x(), R.top() + R.height() / 2)

            background[self.IndexT] = QtCore.QPointF(background[self.IndexT].x(), R.top())
            background[self.IndexL] = QtCore.QPointF(background[self.IndexL].x(), R.top() + R.height() / 2)
            background[self.IndexE] = QtCore.QPointF(background[self.IndexE].x(), R.top() + R.height() / 2)
            background[self.IndexR] = QtCore.QPointF(background[self.IndexR].x(), R.top() + R.height() / 2)
            
            polygon[self.IndexT] = QtCore.QPointF(polygon[self.IndexT].x(), R.top() + 4)
            polygon[self.IndexL] = QtCore.QPointF(polygon[self.IndexL].x(), R.top() + R.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(polygon[self.IndexE].x(), R.top() + R.height() / 2)
            polygon[self.IndexR] = QtCore.QPointF(polygon[self.IndexR].x(), R.top() + R.height() / 2)

        elif self.mp_Handle == self.HandleTR:

            fromX = self.mp_Bound.right()
            fromY = self.mp_Bound.top()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, +4, snap)
            toY = snapF(toY, size, -4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            selection[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2, R.top())
            selection[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2, selection[self.IndexB].y())
            selection[self.IndexL] = QtCore.QPointF(selection[self.IndexL].x(), R.top() + R.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(selection[self.IndexE].x(), R.top() + R.height() / 2)
            selection[self.IndexR] = QtCore.QPointF(R.right(), R.top() + R.height() / 2)

            background[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2, R.top())
            background[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2, background[self.IndexB].y())
            background[self.IndexL] = QtCore.QPointF(background[self.IndexL].x(), R.top() + R.height() / 2)
            background[self.IndexE] = QtCore.QPointF(background[self.IndexE].x(), R.top() + R.height() / 2)
            background[self.IndexR] = QtCore.QPointF(R.right(), R.top() + R.height() / 2)
            
            polygon[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2, R.top() + 4)
            polygon[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2, polygon[self.IndexB].y())
            polygon[self.IndexL] = QtCore.QPointF(polygon[self.IndexL].x(), R.top() + R.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(polygon[self.IndexE].x(), R.top() + R.height() / 2)
            polygon[self.IndexR] = QtCore.QPointF(R.right() - 4, R.top() + R.height() / 2)

        elif self.mp_Handle == self.HandleML:

            fromX = self.mp_Bound.left()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toX = snapF(toX, size, -4, snap)
            D.setX(toX - fromX)
            R.setLeft(toX)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())

            selection[self.IndexL] = QtCore.QPointF(R.left(), self.mp_Bound.top() + self.mp_Bound.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(R.left(), self.mp_Bound.top() + self.mp_Bound.height() / 2)
            selection[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2, selection[self.IndexT].y())
            selection[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2, selection[self.IndexB].y())
            
            background[self.IndexL] = QtCore.QPointF(R.left(), self.mp_Bound.top() + self.mp_Bound.height() / 2)
            background[self.IndexE] = QtCore.QPointF(R.left(), self.mp_Bound.top() + self.mp_Bound.height() / 2)
            background[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2, background[self.IndexT].y())
            background[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2, background[self.IndexB].y())
            
            polygon[self.IndexL] = QtCore.QPointF(R.left() + 4, self.mp_Bound.top() + self.mp_Bound.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(R.left() + 4, self.mp_Bound.top() + self.mp_Bound.height() / 2)
            polygon[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2, polygon[self.IndexT].y())
            polygon[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2, polygon[self.IndexB].y())

        elif self.mp_Handle == self.HandleMR:

            fromX = self.mp_Bound.right()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toX = snapF(toX, size, +4, snap)
            D.setX(toX - fromX)
            R.setRight(toX)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())

            selection[self.IndexR] = QtCore.QPointF(R.right(), self.mp_Bound.top() + self.mp_Bound.height() / 2)
            selection[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2, selection[self.IndexT].y())
            selection[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2, selection[self.IndexB].y())
            
            background[self.IndexR] = QtCore.QPointF(R.right(), self.mp_Bound.top() + self.mp_Bound.height() / 2)
            background[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2, background[self.IndexT].y())
            background[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2, background[self.IndexB].y())
            
            polygon[self.IndexR] = QtCore.QPointF(R.right() - 4, self.mp_Bound.top() + self.mp_Bound.height() / 2)
            polygon[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2, polygon[self.IndexT].y())
            polygon[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2, polygon[self.IndexB].y())

        elif self.mp_Handle == self.HandleBL:

            fromX = self.mp_Bound.left()
            fromY = self.mp_Bound.bottom()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, -4, snap)
            toY = snapF(toY, size, +4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            selection[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2, selection[self.IndexT].y())
            selection[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2, R.bottom())
            selection[self.IndexL] = QtCore.QPointF(R.left(), R.bottom() - R.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(R.left(), R.bottom() - R.height() / 2)
            selection[self.IndexR] = QtCore.QPointF(selection[self.IndexR].x(), R.bottom() - R.height() / 2)
            
            background[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2, background[self.IndexT].y())
            background[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2, R.bottom())
            background[self.IndexL] = QtCore.QPointF(R.left(), R.bottom() - R.height() / 2)
            background[self.IndexE] = QtCore.QPointF(R.left(), R.bottom() - R.height() / 2)
            background[self.IndexR] = QtCore.QPointF(background[self.IndexR].x(), R.bottom() - R.height() / 2)
            
            polygon[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2, polygon[self.IndexT].y())
            polygon[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2, R.bottom() - 4)
            polygon[self.IndexL] = QtCore.QPointF(R.left() + 4, R.bottom() - R.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(R.left() + 4, R.bottom() - R.height() / 2)
            polygon[self.IndexR] = QtCore.QPointF(polygon[self.IndexR].x(), R.bottom() - R.height() / 2)

        elif self.mp_Handle == self.HandleBM:

            fromY = self.mp_Bound.bottom()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toY = snapF(toY, size, +4, snap)
            D.setY(toY - fromY)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            selection[self.IndexB] = QtCore.QPointF(selection[self.IndexB].x(), R.bottom())
            selection[self.IndexL] = QtCore.QPointF(selection[self.IndexL].x(), R.top() + R.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(selection[self.IndexE].x(), R.top() + R.height() / 2)
            selection[self.IndexR] = QtCore.QPointF(selection[self.IndexR].x(), R.top() + R.height() / 2)

            background[self.IndexB] = QtCore.QPointF(background[self.IndexB].x(), R.bottom())
            background[self.IndexL] = QtCore.QPointF(background[self.IndexL].x(), R.top() + R.height() / 2)
            background[self.IndexE] = QtCore.QPointF(background[self.IndexE].x(), R.top() + R.height() / 2)
            background[self.IndexR] = QtCore.QPointF(background[self.IndexR].x(), R.top() + R.height() / 2)
            
            polygon[self.IndexB] = QtCore.QPointF(polygon[self.IndexB].x(), R.bottom() - 4)
            polygon[self.IndexL] = QtCore.QPointF(polygon[self.IndexL].x(), R.top() + R.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(polygon[self.IndexE].x(), R.top() + R.height() / 2)
            polygon[self.IndexR] = QtCore.QPointF(polygon[self.IndexR].x(), R.top() + R.height() / 2)

        elif self.mp_Handle == self.HandleBR:

            fromX = self.mp_Bound.right()
            fromY = self.mp_Bound.bottom()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, +4, snap)
            toY = snapF(toY, size, +4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            selection[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2, selection[self.IndexT].y())
            selection[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2, R.bottom())
            selection[self.IndexL] = QtCore.QPointF(selection[self.IndexL].x(), R.bottom() - R.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(selection[self.IndexE].x(), R.bottom() - R.height() / 2)
            selection[self.IndexR] = QtCore.QPointF(R.right(), R.bottom() - R.height() / 2)

            background[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2, background[self.IndexT].y())
            background[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2, R.bottom())
            background[self.IndexL] = QtCore.QPointF(background[self.IndexL].x(), R.bottom() - R.height() / 2)
            background[self.IndexE] = QtCore.QPointF(background[self.IndexE].x(), R.bottom() - R.height() / 2)
            background[self.IndexR] = QtCore.QPointF(R.right(), R.bottom() - R.height() / 2)
            
            polygon[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2, polygon[self.IndexT].y())
            polygon[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2, R.bottom() - 4)
            polygon[self.IndexL] = QtCore.QPointF(polygon[self.IndexL].x(), R.bottom() - R.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(polygon[self.IndexE].x(), R.bottom() - R.height() / 2)
            polygon[self.IndexR] = QtCore.QPointF(R.right() - 4, R.bottom() - R.height() / 2)

        self.background.setGeometry(background)
        self.selection.setGeometry(selection)
        self.polygon.setGeometry(polygon)

        self.updateNode(selected=True, handle=self.mp_Handle, anchors=(self.mp_Data, D))
        self.updateTextPos(moved=moved)

    def setAsymmetric(self, asymmetric):
        """
        Set the asymmetric property for the predicate represented by this node.
        :type asymmetric: bool
        """
        meta = self.project.meta(self.type(), self.text())
        meta['asymmetric'] = bool(asymmetric)
        self.project.setMeta(self.type(), self.text(), meta)

    def setFunctional(self, functional):
        """
        Set the functional property of the predicate represented by this node.
        :type functional: bool
        """
        meta = self.project.meta(self.type(), self.text())
        meta['functional'] = bool(functional)
        self.project.setMeta(self.type(), self.text(), meta)
        for node in self.project.predicates(self.type(), self.text()):
            node.updateNode(functional=functional, selected=node.isSelected())

    def setIdentity(self, identity):
        """
        Set the identity of the current node.
        :type identity: Identity
        """
        pass

    def setInverseFunctional(self, inverseFunctional):
        """
        Set the inverse functional property of the predicate represented by this node.
        :type inverseFunctional: bool
        """
        meta = self.project.meta(self.type(), self.text())
        meta['inverseFunctional'] = bool(inverseFunctional)
        self.project.setMeta(self.type(), self.text(), meta)
        for node in self.project.predicates(self.type(), self.text()):
            node.updateNode(inverseFunctional=inverseFunctional, selected=node.isSelected())

    def setIrreflexive(self, irreflexive):
        """
        Set the irreflexive property for the predicate represented by this node.
        :type irreflexive: bool
        """
        meta = self.project.meta(self.type(), self.text())
        meta['irreflexive'] = bool(irreflexive)
        self.project.setMeta(self.type(), self.text(), meta)

    def setReflexive(self, reflexive):
        """
        Set the reflexive property for the predicate represented by this node.
        :type reflexive: bool
        """
        meta = self.project.meta(self.type(), self.text())
        meta['reflexive'] = bool(reflexive)
        self.project.setMeta(self.type(), self.text(), meta)

    def setSymmetric(self, symmetric):
        """
        Set the symmetric property for the predicate represented by this node.
        :type symmetric: bool
        """
        meta = self.project.meta(self.type(), self.text())
        meta['symmetric'] = bool(symmetric)
        self.project.setMeta(self.type(), self.text(), meta)

    def setTransitive(self, transitive):
        """
        Set the transitive property for the predicate represented by this node.
        :type transitive: bool
        """
        meta = self.project.meta(self.type(), self.text())
        meta['transitive'] = bool(transitive)
        self.project.setMeta(self.type(), self.text(), meta)

    def setText(self, text):
        """
        Set the label text.
        :type text: str
        """
        self.label.setText(text)

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        self.label.setPos(pos)
        self.label.setAlignment(QtCore.Qt.AlignCenter)

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        for polygon in self.handles:
            path.addEllipse(polygon.geometry())
        return path

    def special(self):
        """
        Returns the special type of this node.
        :rtype: Special
        """
        return Special.forValue(self.text())

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        return self.label.text()

    def textPos(self):
        """
        Returns the current label position in item coordinates.
        :rtype: QPointF
        """
        return self.label.pos()

    def updateNode(self, functional=None, inverseFunctional=None, **kwargs):
        """
        Update the current node.
        :type functional: bool
        :type inverseFunctional: bool
        """
        if functional is None:
            functional = self.isFunctional()
        if inverseFunctional is None:
            inverseFunctional = self.isInverseFunctional()

        polygon = self.polygon.geometry()

        # FUNCTIONAL POLYGON (SHAPE)
        fpolygon = QtGui.QPainterPath()
        if functional and not inverseFunctional:
            path = QtGui.QPainterPath()
            path.addPolygon(QtGui.QPolygonF([
                polygon[self.IndexL] + QtCore.QPointF(+5, 0),
                polygon[self.IndexB] + QtCore.QPointF(0, -4),
                polygon[self.IndexR] + QtCore.QPointF(-5, 0),
                polygon[self.IndexT] + QtCore.QPointF(0, +4),
                polygon[self.IndexL] + QtCore.QPointF(+5, 0),
            ]))
            fpolygon.addPolygon(polygon)
            fpolygon = fpolygon.subtracted(path)

        # INVERSE FUNCTIONAL POLYGON (SHAPE)
        ipolygon = QtGui.QPainterPath()
        if not functional and inverseFunctional:
            path = QtGui.QPainterPath()
            path.addPolygon(QtGui.QPolygonF([
                polygon[self.IndexL] + QtCore.QPointF(+5, 0),
                polygon[self.IndexB] + QtCore.QPointF(0, -4),
                polygon[self.IndexR] + QtCore.QPointF(-5, 0),
                polygon[self.IndexT] + QtCore.QPointF(0, +4),
                polygon[self.IndexL] + QtCore.QPointF(+5, 0),
            ]))
            ipolygon.addPolygon(polygon)
            ipolygon = ipolygon.subtracted(path)

        # FUNCTIONAL + INVERSE FUNCTIONAL POLYGONS (SHAPE)
        if functional and inverseFunctional:
            path = QtGui.QPainterPath()
            path.addPolygon(QtGui.QPolygonF([
                polygon[self.IndexL] + QtCore.QPointF(+5, 0),
                polygon[self.IndexB] + QtCore.QPointF(0, -4),
                polygon[self.IndexB],
                polygon[self.IndexR],
                polygon[self.IndexT],
                polygon[self.IndexT] + QtCore.QPointF(0, +4),
                polygon[self.IndexL] + QtCore.QPointF(+5, 0),
            ]))
            fpolygon.addPolygon(polygon)
            fpolygon = fpolygon.subtracted(path)
            path = QtGui.QPainterPath()
            path.addPolygon(QtGui.QPolygonF([
                polygon[self.IndexL],
                polygon[self.IndexB],
                polygon[self.IndexB] + QtCore.QPointF(0, -4),
                polygon[self.IndexR] + QtCore.QPointF(-5, 0),
                polygon[self.IndexT] + QtCore.QPointF(0, +4),
                polygon[self.IndexT],
                polygon[self.IndexL],
            ]))
            ipolygon.addPolygon(polygon)
            ipolygon = ipolygon.subtracted(path)

        # FUNCTIONAL POLYGON (PEN + BRUSH)
        fpen = QtGui.QPen(QtCore.Qt.NoPen)
        fbrush = QtGui.QBrush(QtCore.Qt.NoBrush)
        if functional:
            fpen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
            fbrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))

        # INVERSE FUNCTIONAL POLYGON (PEN + BRUSH)
        ipen = QtGui.QPen(QtCore.Qt.NoPen)
        ibrush = QtGui.QBrush(QtCore.Qt.NoBrush)
        if inverseFunctional:
            ipen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
            ibrush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 255))

        self.fpolygon.setPen(fpen)
        self.fpolygon.setBrush(fbrush)
        self.fpolygon.setGeometry(fpolygon)
        self.ipolygon.setPen(ipen)
        self.ipolygon.setBrush(ibrush)
        self.ipolygon.setGeometry(ipolygon)

        # SELECTION + BACKGROUND + HANDLES + ANCHORS + CACHE REFRESH
        super().updateNode(**kwargs)

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        self.label.updatePos(*args, **kwargs)

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        polygon = self.polygon.geometry()
        return polygon[self.IndexR].x() - polygon[self.IndexL].x()

    def __repr__(self):
        """
        Returns repr(self).
        """
        return '{0}:{1}:{2}'.format(self.__class__.__name__, self.text(), self.id)
Exemple #14
0
class ValueDomainNode(AbstractNode):
    """
    This class implements the 'Value-Domain' node.
    """
    DefaultBrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.0,
                            QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                            QtCore.Qt.RoundJoin)
    Identities = {Identity.ValueDomain}
    Type = Item.ValueDomainNode

    def __init__(self, width=90, height=40, brush=None, **kwargs):
        """
        Initialize the ValueDomain node.
        :type width: int
        :type height: int
        :type brush: QBrush
        """
        super().__init__(**kwargs)
        brush = brush or ValueDomainNode.DefaultBrush
        pen = ValueDomainNode.DefaultPen
        self.background = Polygon(QtCore.QRectF(-49, -24, 98, 48))
        self.selection = Polygon(QtCore.QRectF(-49, -24, 98, 48))
        self.polygon = Polygon(QtCore.QRectF(-45, -20, 90, 40), brush, pen)
        self.label = NodeLabel(Datatype.string.value,
                               pos=self.center,
                               editable=False,
                               movable=False,
                               parent=self)
        self.updateNode()
        self.updateTextPos()

    #############################################
    #   PROPERTIES
    #################################

    @property
    def datatype(self):
        """
        Returns the datatype associated with this node.
        :rtype: Datatype
        """
        return Datatype.valueOf(self.text())

    #############################################
    #   INTERFACE
    #################################

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QtCore.QRectF
        """
        return self.selection.geometry()

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        node = diagram.factory.create(
            self.type(), **{
                'id': self.id,
                'brush': self.brush(),
                'height': self.height(),
                'width': self.width()
            })
        node.setPos(self.pos())
        node.setText(self.text())
        node.setTextPos(node.mapFromScene(self.mapToScene(self.textPos())))
        return node

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        return self.polygon.geometry().height()

    def identity(self):
        """
        Returns the identity of the current node.
        :rtype: Identity
        """
        return Identity.ValueDomain

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawRoundedRect(self.selection.geometry(), 8, 8)
        # SYNTAX VALIDATION
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawRoundedRect(self.background.geometry(), 8, 8)
        # SHAPE
        painter.setPen(self.polygon.pen())
        painter.setBrush(self.polygon.brush())
        painter.drawRoundedRect(self.polygon.geometry(), 8, 8)

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addRoundedRect(self.polygon.geometry(), 8, 8)
        return path

    def setIdentity(self, identity):
        """
        Set the identity of the current node.
        :type identity: Identity
        """
        pass

    def setText(self, text):
        """
        Set the label text.
        :type text: str
        """
        datatype = Datatype.valueOf(text) or Datatype.string
        self.label.setText(datatype.value)
        self.updateNode()

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        self.label.setPos(pos)

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addRoundedRect(self.polygon.geometry(), 8, 8)
        return path

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        return self.label.text()

    def textPos(self):
        """
        Returns the current label position in item coordinates.
        :rtype: QPointF
        """
        return self.label.pos()

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        self.label.updatePos(*args, **kwargs)

    def updateNode(self, *args, **kwargs):
        """
        Update the current node.
        """
        # POLYGON + BACKGROUND + SELECTION (GEOMETRY)
        width = max(self.label.width() + 16, 90)
        self.polygon.setGeometry(QtCore.QRectF(-width / 2, -20, width, 40))
        self.background.setGeometry(
            QtCore.QRectF(-(width + 8) / 2, -24, width + 8, 48))
        self.selection.setGeometry(
            QtCore.QRectF(-(width + 8) / 2, -24, width + 8, 48))
        self.updateTextPos()
        self.updateEdges()

        # SELECTION + BACKGROUND + CACHE REFRESH
        super().updateNode(**kwargs)

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        return self.polygon.geometry().width()

    def __repr__(self):
        """
        Returns repr(self).
        """
        return '{0}:{1}:{2}'.format(self.__class__.__name__, self.text(),
                                    self.id)
class PropertyAssertionNode(AbstractNode):
    """
    This class implements the 'Property Assertion' node.
    """
    DefaultBrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.0, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
    Identities = {Identity.RoleInstance, Identity.AttributeInstance, Identity.Neutral}
    Type = Item.PropertyAssertionNode

    def __init__(self, width=52, height=30, brush=None, inputs=None, **kwargs):
        """
        Initialize the node.
        :type width: int
        :type height: int
        :type brush: QBrush
        :type inputs: DistinctList
        """
        super().__init__(**kwargs)
        brush = PropertyAssertionNode.DefaultBrush
        pen = PropertyAssertionNode.DefaultPen
        self.inputs = inputs or DistinctList()
        self.background = Polygon(QtCore.QRectF(-34, -19, 68, 38))
        self.selection = Polygon(QtCore.QRectF(-34, -19, 68, 38))
        self.polygon = Polygon(QtCore.QRectF(-26, -15, 52, 30), brush, pen)

    #############################################
    #   INTERFACE
    #################################

    def addEdge(self, edge):
        """
        Add the given edge to the current node.
        :type edge: AbstractEdge
        """
        super().addEdge(edge)
        if edge.type() is Item.InputEdge and edge.target is self:
            self.inputs.append(edge.id)
            edge.updateEdge()

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QtCore.QRectF
        """
        return self.selection.geometry()

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        kwargs = {'id': self.id, 'height': self.height(), 'width': self.width()}
        node = diagram.factory.create(self.type(), **kwargs)
        node.setPos(self.pos())
        return node

    def definition(self):
        """
        Returns the list of nodes which contribute to the definition of this very node.
        :rtype: set
        """
        return set(self.incomingNodes(filter_on_edges=lambda x: x.type() is Item.InputEdge))

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        return self.polygon.geometry().height()

    def identify(self):
        """
        Perform the node identification step for this PropertyAssertion node.
        The identity of the node is calculated as follows:

        * If the node is targeting a Role with a membership edge => Identity == RoleInstance
        * If the node is targeting an Attribute with a membership edge => Identity == AttributeInstance

        else

        * If the node has 2 individuals as inputs => Identity == RoleInstance
        * If the node has 1 individual and 1 value as inputs => Identity == AttributeInstance

        In both the cases, whether we establish or not an idendity for this node,
        we mark it for EXCLUSION from the STRONG and WEAK sets. This is due to the
        PropertyAssertion node being used to perform assertions at ABox level
        while every other node in the graph is used at TBox level. Additionally we
        discard the inputs of this node from the STRONG set because they are either
        Individual or Value nodes and they are not needed to compute the final identity
        for all the WEAK nodes being examined during the identification process.
        :rtype: tuple
        """
        f1 = lambda x: x.type() is Item.MembershipEdge
        f2 = lambda x: x.type() in {Item.RoleNode, Item.RoleInverseNode, Item.AttributeNode}
        f3 = lambda x: x.type() is Item.InputEdge
        f4 = lambda x: x.type() is Item.IndividualNode
        f5 = lambda x: Identity.RoleInstance if x.identity() is Identity.Role else Identity.AttributeInstance
        f6 = lambda x: x.identity() is Identity.Value
        outgoing = self.outgoingNodes(filter_on_edges=f1, filter_on_nodes=f2)
        incoming = self.incomingNodes(filter_on_edges=f3, filter_on_nodes=f4)
        computed = Identity.Neutral
        # 1) USE MEMBERSHIP EDGE
        identities = set(map(f5, outgoing))
        if identities:
            computed = first(identities)
            if len(identities) > 1:
                computed = Identity.Unknown
        # 2) USE INPUT EDGES
        if computed is Identity.Neutral and len(incoming) >= 2:
            computed = Identity.RoleInstance
            if sum(map(f6, incoming)):
                computed = Identity.AttributeInstance
        self.setIdentity(computed)
        return set(), incoming, {self}

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawRoundedRect(self.selection.geometry(), 16, 16)
        # SYNTAX VALIDATION
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawRoundedRect(self.background.geometry(), 16, 16)
        # SHAPE
        painter.setPen(self.polygon.pen())
        painter.setBrush(self.polygon.brush())
        painter.drawRoundedRect(self.polygon.geometry(), 16, 16)

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addRoundedRect(self.polygon.geometry(), 16, 16)
        return path

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addRoundedRect(self.polygon.geometry(), 16, 16)
        return path

    def removeEdge(self, edge):
        """
        Remove the given edge from the current node.
        :type edge: AbstractEdge
        """
        super().removeEdge(edge)
        self.inputs.remove(edge.id)
        for i in self.inputs:
            try:
                edge = self.diagram.edge(i)
                edge.updateEdge()
            except KeyError:
                pass

    def setText(self, text):
        """
        Set the label text.
        :type text: str
        """
        pass

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        pass

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        pass

    def textPos(self):
        """
        Returns the current label position in item coordinates.
        :rtype: QPointF
        """
        pass

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        pass

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        return self.polygon.geometry().width()
Exemple #16
0
class FacetNode(AbstractNode):
    """
    This class implements the 'Facet' node.
    """

    IndexTL = 0
    IndexTR = 1
    IndexBR = 2
    IndexBL = 3
    IndexEE = 4

    DefaultBrushA = QtGui.QBrush(QtGui.QColor(222, 222, 222, 255))
    DefaultBrushB = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPenA = QtGui.QPen(
        QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.0, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin
    )
    DefaultPenB = QtGui.QPen(
        QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.0, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin
    )
    Identities = {Identity.Facet}
    Type = Item.FacetNode

    def __init__(self, width=80, height=40, brush=None, **kwargs):
        """
        Initialize the node.
        :type width: int
        :type height: int
        :type brush: QBrush
        """
        super().__init__(**kwargs)
        self.background = Polygon(self.createPolygon(88, 48))
        self.selection = Polygon(self.createPolygon(88, 48))
        self.polygon = Polygon(self.createPolygon(80, 40))
        self.polygonA = Polygon(self.createPolygonA(80, 40), FacetNode.DefaultBrushA, FacetNode.DefaultPenA)
        self.polygonB = Polygon(self.createPolygonA(80, 40), FacetNode.DefaultBrushB, FacetNode.DefaultPenB)
        self.labelA = NodeLabel(Facet.length.value, pos=self.centerA, editable=False, movable=False, parent=self)
        self.labelB = FacetQuotedLabel(template='"32"', movable=False, pos=self.centerB, parent=self)
        self.updateNode()
        self.updateTextPos()

    #############################################
    #   PROPERTIES
    #################################

    @property
    def datatype(self):
        """
        Returns the datatype this facet is restricting, or None if the node is isolated.
        :rtype: Datatype
        """
        f1 = lambda x: x.type() is Item.InputEdge
        f2 = lambda x: x.type() is Item.DatatypeRestrictionNode
        f3 = lambda x: x.type() is Item.ValueDomainNode
        outgoing = first(self.outgoingNodes(filter_on_edges=f1, filter_on_nodes=f2))
        if outgoing:
            incoming = first(outgoing.incomingNodes(filter_on_edges=f1, filter_on_nodes=f3))
            if incoming:
                return incoming.datatype
        return None

    @property
    def facet(self):
        """
        Returns the facet associated with this node.
        :rtype: Facet
        """
        return Facet.forValue(self.labelA.text())

    @property
    def value(self):
        """
        Returns the value of this facet node.
        :rtype: str
        """
        return self.labelB.text().strip('"')

    #############################################
    #   INTERFACE
    #################################

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QtCore.QRectF
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.selection.geometry())
        return path.boundingRect()

    def brushA(self):
        """
        Returns the brush used to paint the shape A of this node.
        :rtype: QtGui.QBrush
        """
        return self.polygonA.brush()

    def brushB(self):
        """
        Returns the brush used to paint the shape B of this node.
        :rtype: QtGui.QBrush
        """
        return self.polygonB.brush()

    def centerA(self):
        """
        Returns the center point of polygon A.
        :rtype: QPointF
        """
        return self.boundingRect().center() - QtCore.QPointF(0, 40 / 4)

    def centerB(self):
        """
        Returns the center point of polygon A.
        :rtype: QPointF
        """
        return self.boundingRect().center() + QtCore.QPointF(0, 40 / 4)

    @staticmethod
    def compose(facet, value):
        """
        Compose the restriction string.
        :type facet: Facet
        :type value: str
        :return: str
        """
        return '{0}^^"{1}"'.format(facet.value, value.strip().strip('"'))

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        node = diagram.factory.create(self.type(), **{"id": self.id, "height": self.height(), "width": self.width()})
        node.setPos(self.pos())
        node.setText(self.text())
        node.updateNode()
        node.setTextPos(node.mapFromScene(self.mapToScene(self.textPos())))
        return node

    def definition(self):
        """
        Returns the list of nodes which contribute to the definition of this very node.
        :rtype: set
        """
        return set(self.incomingNodes(filter_on_edges=lambda x: x.type() is Item.InputEdge))

    @staticmethod
    def createPolygon(w, h):
        """
        Returns the initialized polygon according to the given width/height.
        :type w: int
        :type h: int
        :rtype: QtGui.QPolygonF
        """
        return QtGui.QPolygonF(
            [
                QtCore.QPointF(-w / 2 + 10, -h / 2),
                QtCore.QPointF(+w / 2, -h / 2),
                QtCore.QPointF(+w / 2 - 10, +h / 2),
                QtCore.QPointF(-w / 2, +h / 2),
                QtCore.QPointF(-w / 2 + 10, -h / 2),
            ]
        )

    @staticmethod
    def createPolygonA(w, h):
        """
        Returns the initialized top-half polygon according to the given width/height.
        :type w: int
        :type h: int
        :rtype: QtGui.QPolygonF
        """
        return QtGui.QPolygonF(
            [
                QtCore.QPointF(-w / 2 + 10, -h / 2),
                QtCore.QPointF(+w / 2, -h / 2),
                QtCore.QPointF(+w / 2 - 10 / 2, 0),
                QtCore.QPointF(-w / 2 + 10 / 2, 0),
                QtCore.QPointF(-w / 2 + 10, -h / 2),
            ]
        )

    @staticmethod
    def createPolygonB(w, h):
        """
        Returns the initialized bottom-half polygon according to the given width/height.
        :type w: int
        :type h: int
        :rtype: QtGui.QPolygonF
        """
        return QtGui.QPolygonF(
            [
                QtCore.QPointF(-w / 2 + 10 / 2, 0),
                QtCore.QPointF(+w / 2 - 10 / 2, 0),
                QtCore.QPointF(+w / 2 - 10, +h / 2),
                QtCore.QPointF(-w / 2, +h / 2),
                QtCore.QPointF(-w / 2 + 10 / 2, 0),
            ]
        )

    def geometryA(self):
        """
        Returns the geometry of the shape A of this node.
        :rtype: QtGui.QPolygonF
        """
        return self.polygonA.geometry()

    def geometryB(self):
        """
        Returns the geometry of the shape B of this node.
        :rtype: QtGui.QPolygonF
        """
        return self.polygonB.geometry()

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        polygonA = self.polygonA.geometry()
        polygonB = self.polygonB.geometry()
        return polygonA[self.IndexBL].y() - polygonB[self.IndexTL].y()

    def identity(self):
        """
        Returns the identity of the current node.
        :rtype: Identity
        """
        return Identity.Facet

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawPolygon(self.selection.geometry())
        # SYNTAX VALIDATION
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawPolygon(self.background.geometry())
        # SHAPE
        painter.setPen(self.polygonA.pen())
        painter.setBrush(self.polygonA.brush())
        painter.drawPolygon(self.polygonA.geometry())
        painter.setPen(self.polygonB.pen())
        painter.setBrush(self.polygonB.brush())
        painter.drawPolygon(self.polygonB.geometry())

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        return path

    def penA(self):
        """
        Returns the pen used to paint the shape A of this node.
        :rtype: QtGui.QPen
        """
        return self.polygonA.pen()

    def penB(self):
        """
        Returns the pen used to paint the shape B of this node.
        :rtype: QtGui.QPen
        """
        return self.polygonB.pen()

    def setIdentity(self, identity):
        """
        Set the identity of the current node.
        :type identity: Identity
        """
        pass

    def setText(self, text):
        """
        Set the label text.
        :type text: str
        """
        match = RE_FACET.match(text)
        if match:
            self.labelA.setText((Facet.forValue(match.group("facet")) or Facet.length).value)
            self.labelB.setText('"{0}"'.format(match.group("value")))
            self.updateNode()
        else:
            # USE THE OLD VALUE-RESTRICTION PATTERN
            match = RE_VALUE_RESTRICTION.match(text)
            if match:
                self.labelA.setText((Facet.forValue(match.group("facet")) or Facet.length).value)
                self.labelB.setText('"{0}"'.format(match.group("value")))
                self.updateNode()

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        pass

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        return path

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        return self.compose(self.facet, self.value)

    def textPos(self):
        """
        Returns the current label position in item coordinates.
        :rtype: QPointF
        """
        return self.boundingRect().center()

    def updateNode(self, *args, **kwargs):
        """
        Update the current node.
        """
        # POLYGONS + BACKGROUND + SELECTION (GEOMETRY)
        width = max(self.labelA.width() + 16, self.labelB.width() + 16, 80)
        self.background.setGeometry(self.createPolygon(width + 8, 48))
        self.selection.setGeometry(self.createPolygon(width + 8, 48))
        self.polygon.setGeometry(self.createPolygon(width, 40))
        self.polygonA.setGeometry(self.createPolygonA(width, 40))
        self.polygonB.setGeometry(self.createPolygonB(width, 40))
        self.updateTextPos()
        self.updateEdges()

        # SELECTION + BACKGROUND + CACHE REFRESH
        super().updateNode(**kwargs)

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        self.labelA.updatePos()
        self.labelB.updatePos()

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        polygonA = self.polygonA.geometry()
        polygonB = self.polygonB.geometry()
        return polygonA[self.IndexTR].x() - polygonB[self.IndexBL].x()
Exemple #17
0
class RoleNode(AbstractResizableNode):
    """
    This class implements the 'Role' node.
    """
    IndexL = 0
    IndexB = 1
    IndexR = 2
    IndexT = 3
    IndexE = 4

    DefaultBrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1,
                            QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                            QtCore.Qt.RoundJoin)
    Identities = {Identity.Role}
    Type = Item.RoleNode

    def __init__(self,
                 width=70,
                 height=50,
                 brush=None,
                 remaining_characters='role',
                 **kwargs):
        """
        Initialize the node.
        :type width: int
        :type height: int
        :type brush: QBrush
        """
        super().__init__(**kwargs)

        w = max(width, 70)
        h = max(height, 50)
        brush = brush or RoleNode.DefaultBrush
        pen = RoleNode.DefaultPen

        createPolygon = lambda x, y: QtGui.QPolygonF([
            QtCore.QPointF(-x / 2, 0),
            QtCore.QPointF(0, +y / 2),
            QtCore.QPointF(+x / 2, 0),
            QtCore.QPointF(0, -y / 2),
            QtCore.QPointF(-x / 2, 0)
        ])

        self.fpolygon = Polygon(QtGui.QPainterPath())
        self.ipolygon = Polygon(QtGui.QPainterPath())
        self.background = Polygon(createPolygon(w + 8, h + 8))
        self.selection = Polygon(createPolygon(w + 8, h + 8))
        self.polygon = Polygon(createPolygon(w, h), brush, pen)

        self.remaining_characters = remaining_characters

        self.label = NodeLabel(template='role',
                               pos=self.center,
                               parent=self,
                               editable=True)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.updateNode()
        self.updateTextPos()

    #############################################
    #   INTERFACE
    #################################

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QtCore.QRectF
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.selection.geometry())
        return path.boundingRect()

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        node = diagram.factory.create(
            self.type(), **{
                'id': self.id,
                'brush': self.brush(),
                'height': self.height(),
                'width': self.width(),
                'remaining_characters': self.remaining_characters,
            })
        node.setPos(self.pos())
        node.setText(self.text())
        node.setTextPos(node.mapFromScene(self.mapToScene(self.textPos())))
        return node

    def definition(self):
        """
        Returns the list of nodes which contribute to the definition of this very node.
        :rtype: set
        """
        f1 = lambda x: x.type() is Item.InputEdge
        f2 = lambda x: x.type(
        ) in {Item.DomainRestrictionNode, Item.RangeRestrictionNode}
        return self.outgoingNodes(filter_on_edges=f1, filter_on_nodes=f2)

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        polygon = self.polygon.geometry()
        return polygon[self.IndexB].y() - polygon[self.IndexT].y()

    def identity(self):
        """
        Returns the identity of the current node.
        :rtype: Identity
        """
        return Identity.Role

    def isAsymmetric(self):
        """
        Returns True if the predicate represented by this node is asymmetric, False otherwise.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(), self.text())[K_ASYMMETRIC]
        except (AttributeError, KeyError):
            return False

    def isFunctional(self):
        """
        Returns True if the predicate represented by this node is functional, else False.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(),
                                     self.text())[K_FUNCTIONAL]  #and \
            #self.project.profile.type() is not OWLProfile.OWL2QL
        except (AttributeError, KeyError):
            return False

    def isInverseFunctional(self):
        """
        Returns True if the predicate represented by this node is inverse functional, else False.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(),
                                     self.text())[K_INVERSE_FUNCTIONAL]  #and \
            #self.project.profile.type() is not OWLProfile.OWL2QL
        except (AttributeError, KeyError):
            return False

    def isIrreflexive(self):
        """
        Returns True if the predicate represented by this node is irreflexive, False otherwise.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(), self.text())[K_IRREFLEXIVE]
        except (AttributeError, KeyError):
            return False

    def isReflexive(self):
        """
        Returns True if the predicate represented by this node is reflexive, False otherwise.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(),
                                     self.text())[K_REFLEXIVE]  #and \
            #self.project.profile.type() is not OWLProfile.OWL2RL
        except (AttributeError, KeyError):
            return False

    def isSymmetric(self):
        """
        Returns True if the predicate represented by this node is symmetric, False otherwise.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(), self.text())[K_SYMMETRIC]
        except (AttributeError, KeyError):
            return False

    def isTransitive(self):
        """
        Returns True if the transitive represented by this node is symmetric, False otherwise.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(),
                                     self.text())[K_TRANSITIVE]  #and \
            #self.project.profile.type() is not OWLProfile.OWL2QL
        except (AttributeError, KeyError):
            return False

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawPolygon(self.selection.geometry())
        # SYNTAX VALIDATION
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawPolygon(self.background.geometry())
        # ITEM SHAPE
        painter.setPen(self.polygon.pen())
        painter.setBrush(self.polygon.brush())
        painter.drawPolygon(self.polygon.geometry())
        # FUNCTIONALITY
        painter.setPen(self.fpolygon.pen())
        painter.setBrush(self.fpolygon.brush())
        painter.drawPath(self.fpolygon.geometry())
        # INVERSE FUNCTIONALITY
        painter.setPen(self.ipolygon.pen())
        painter.setBrush(self.ipolygon.brush())
        painter.drawPath(self.ipolygon.geometry())
        # RESIZE HANDLES
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        for polygon in self.handles:
            painter.setPen(polygon.pen())
            painter.setBrush(polygon.brush())
            painter.drawEllipse(polygon.geometry())

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        return path

    def resize(self, mousePos):
        """
        Handle the interactive resize of the shape.
        :type mousePos: QtCore.QPointF
        """
        snap = self.session.action('toggle_grid').isChecked()
        size = self.diagram.GridSize
        moved = self.label.isMoved()

        background = self.background.geometry()
        selection = self.selection.geometry()
        polygon = self.polygon.geometry()

        R = QtCore.QRectF(self.boundingRect())
        D = QtCore.QPointF(0, 0)

        mbrh = 58
        mbrw = 78

        self.prepareGeometryChange()

        if self.mp_Handle == self.HandleTL:

            fromX = self.mp_Bound.left()
            fromY = self.mp_Bound.top()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, -4, snap)
            toY = snapF(toY, size, -4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            selection[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2,
                                                    R.top())
            selection[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2,
                                                    selection[self.IndexB].y())
            selection[self.IndexL] = QtCore.QPointF(R.left(),
                                                    R.top() + R.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(R.left(),
                                                    R.top() + R.height() / 2)
            selection[self.IndexR] = QtCore.QPointF(selection[self.IndexR].x(),
                                                    R.top() + R.height() / 2)

            background[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2,
                                                     R.top())
            background[self.IndexB] = QtCore.QPointF(
                R.left() + R.width() / 2, background[self.IndexB].y())
            background[self.IndexL] = QtCore.QPointF(R.left(),
                                                     R.top() + R.height() / 2)
            background[self.IndexE] = QtCore.QPointF(R.left(),
                                                     R.top() + R.height() / 2)
            background[self.IndexR] = QtCore.QPointF(
                background[self.IndexR].x(),
                R.top() + R.height() / 2)

            polygon[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2,
                                                  R.top() + 4)
            polygon[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2,
                                                  polygon[self.IndexB].y())
            polygon[self.IndexL] = QtCore.QPointF(R.left() + 4,
                                                  R.top() + R.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(R.left() + 4,
                                                  R.top() + R.height() / 2)
            polygon[self.IndexR] = QtCore.QPointF(polygon[self.IndexR].x(),
                                                  R.top() + R.height() / 2)

        elif self.mp_Handle == self.HandleTM:

            fromY = self.mp_Bound.top()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toY = snapF(toY, size, -4, snap)
            D.setY(toY - fromY)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            selection[self.IndexT] = QtCore.QPointF(selection[self.IndexT].x(),
                                                    R.top())
            selection[self.IndexL] = QtCore.QPointF(selection[self.IndexL].x(),
                                                    R.top() + R.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(selection[self.IndexE].x(),
                                                    R.top() + R.height() / 2)
            selection[self.IndexR] = QtCore.QPointF(selection[self.IndexR].x(),
                                                    R.top() + R.height() / 2)

            background[self.IndexT] = QtCore.QPointF(
                background[self.IndexT].x(), R.top())
            background[self.IndexL] = QtCore.QPointF(
                background[self.IndexL].x(),
                R.top() + R.height() / 2)
            background[self.IndexE] = QtCore.QPointF(
                background[self.IndexE].x(),
                R.top() + R.height() / 2)
            background[self.IndexR] = QtCore.QPointF(
                background[self.IndexR].x(),
                R.top() + R.height() / 2)

            polygon[self.IndexT] = QtCore.QPointF(polygon[self.IndexT].x(),
                                                  R.top() + 4)
            polygon[self.IndexL] = QtCore.QPointF(polygon[self.IndexL].x(),
                                                  R.top() + R.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(polygon[self.IndexE].x(),
                                                  R.top() + R.height() / 2)
            polygon[self.IndexR] = QtCore.QPointF(polygon[self.IndexR].x(),
                                                  R.top() + R.height() / 2)

        elif self.mp_Handle == self.HandleTR:

            fromX = self.mp_Bound.right()
            fromY = self.mp_Bound.top()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, +4, snap)
            toY = snapF(toY, size, -4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            selection[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2,
                                                    R.top())
            selection[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2,
                                                    selection[self.IndexB].y())
            selection[self.IndexL] = QtCore.QPointF(selection[self.IndexL].x(),
                                                    R.top() + R.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(selection[self.IndexE].x(),
                                                    R.top() + R.height() / 2)
            selection[self.IndexR] = QtCore.QPointF(R.right(),
                                                    R.top() + R.height() / 2)

            background[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2,
                                                     R.top())
            background[self.IndexB] = QtCore.QPointF(
                R.right() - R.width() / 2, background[self.IndexB].y())
            background[self.IndexL] = QtCore.QPointF(
                background[self.IndexL].x(),
                R.top() + R.height() / 2)
            background[self.IndexE] = QtCore.QPointF(
                background[self.IndexE].x(),
                R.top() + R.height() / 2)
            background[self.IndexR] = QtCore.QPointF(R.right(),
                                                     R.top() + R.height() / 2)

            polygon[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2,
                                                  R.top() + 4)
            polygon[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2,
                                                  polygon[self.IndexB].y())
            polygon[self.IndexL] = QtCore.QPointF(polygon[self.IndexL].x(),
                                                  R.top() + R.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(polygon[self.IndexE].x(),
                                                  R.top() + R.height() / 2)
            polygon[self.IndexR] = QtCore.QPointF(R.right() - 4,
                                                  R.top() + R.height() / 2)

        elif self.mp_Handle == self.HandleML:

            fromX = self.mp_Bound.left()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toX = snapF(toX, size, -4, snap)
            D.setX(toX - fromX)
            R.setLeft(toX)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())

            selection[self.IndexL] = QtCore.QPointF(
                R.left(),
                self.mp_Bound.top() + self.mp_Bound.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(
                R.left(),
                self.mp_Bound.top() + self.mp_Bound.height() / 2)
            selection[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2,
                                                    selection[self.IndexT].y())
            selection[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2,
                                                    selection[self.IndexB].y())

            background[self.IndexL] = QtCore.QPointF(
                R.left(),
                self.mp_Bound.top() + self.mp_Bound.height() / 2)
            background[self.IndexE] = QtCore.QPointF(
                R.left(),
                self.mp_Bound.top() + self.mp_Bound.height() / 2)
            background[self.IndexT] = QtCore.QPointF(
                R.left() + R.width() / 2, background[self.IndexT].y())
            background[self.IndexB] = QtCore.QPointF(
                R.left() + R.width() / 2, background[self.IndexB].y())

            polygon[self.IndexL] = QtCore.QPointF(
                R.left() + 4,
                self.mp_Bound.top() + self.mp_Bound.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(
                R.left() + 4,
                self.mp_Bound.top() + self.mp_Bound.height() / 2)
            polygon[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2,
                                                  polygon[self.IndexT].y())
            polygon[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2,
                                                  polygon[self.IndexB].y())

        elif self.mp_Handle == self.HandleMR:

            fromX = self.mp_Bound.right()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toX = snapF(toX, size, +4, snap)
            D.setX(toX - fromX)
            R.setRight(toX)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())

            selection[self.IndexR] = QtCore.QPointF(
                R.right(),
                self.mp_Bound.top() + self.mp_Bound.height() / 2)
            selection[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2,
                                                    selection[self.IndexT].y())
            selection[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2,
                                                    selection[self.IndexB].y())

            background[self.IndexR] = QtCore.QPointF(
                R.right(),
                self.mp_Bound.top() + self.mp_Bound.height() / 2)
            background[self.IndexT] = QtCore.QPointF(
                R.right() - R.width() / 2, background[self.IndexT].y())
            background[self.IndexB] = QtCore.QPointF(
                R.right() - R.width() / 2, background[self.IndexB].y())

            polygon[self.IndexR] = QtCore.QPointF(
                R.right() - 4,
                self.mp_Bound.top() + self.mp_Bound.height() / 2)
            polygon[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2,
                                                  polygon[self.IndexT].y())
            polygon[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2,
                                                  polygon[self.IndexB].y())

        elif self.mp_Handle == self.HandleBL:

            fromX = self.mp_Bound.left()
            fromY = self.mp_Bound.bottom()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, -4, snap)
            toY = snapF(toY, size, +4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            selection[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2,
                                                    selection[self.IndexT].y())
            selection[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2,
                                                    R.bottom())
            selection[self.IndexL] = QtCore.QPointF(
                R.left(),
                R.bottom() - R.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(
                R.left(),
                R.bottom() - R.height() / 2)
            selection[self.IndexR] = QtCore.QPointF(
                selection[self.IndexR].x(),
                R.bottom() - R.height() / 2)

            background[self.IndexT] = QtCore.QPointF(
                R.left() + R.width() / 2, background[self.IndexT].y())
            background[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2,
                                                     R.bottom())
            background[self.IndexL] = QtCore.QPointF(
                R.left(),
                R.bottom() - R.height() / 2)
            background[self.IndexE] = QtCore.QPointF(
                R.left(),
                R.bottom() - R.height() / 2)
            background[self.IndexR] = QtCore.QPointF(
                background[self.IndexR].x(),
                R.bottom() - R.height() / 2)

            polygon[self.IndexT] = QtCore.QPointF(R.left() + R.width() / 2,
                                                  polygon[self.IndexT].y())
            polygon[self.IndexB] = QtCore.QPointF(R.left() + R.width() / 2,
                                                  R.bottom() - 4)
            polygon[self.IndexL] = QtCore.QPointF(R.left() + 4,
                                                  R.bottom() - R.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(R.left() + 4,
                                                  R.bottom() - R.height() / 2)
            polygon[self.IndexR] = QtCore.QPointF(polygon[self.IndexR].x(),
                                                  R.bottom() - R.height() / 2)

        elif self.mp_Handle == self.HandleBM:

            fromY = self.mp_Bound.bottom()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toY = snapF(toY, size, +4, snap)
            D.setY(toY - fromY)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            selection[self.IndexB] = QtCore.QPointF(selection[self.IndexB].x(),
                                                    R.bottom())
            selection[self.IndexL] = QtCore.QPointF(selection[self.IndexL].x(),
                                                    R.top() + R.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(selection[self.IndexE].x(),
                                                    R.top() + R.height() / 2)
            selection[self.IndexR] = QtCore.QPointF(selection[self.IndexR].x(),
                                                    R.top() + R.height() / 2)

            background[self.IndexB] = QtCore.QPointF(
                background[self.IndexB].x(), R.bottom())
            background[self.IndexL] = QtCore.QPointF(
                background[self.IndexL].x(),
                R.top() + R.height() / 2)
            background[self.IndexE] = QtCore.QPointF(
                background[self.IndexE].x(),
                R.top() + R.height() / 2)
            background[self.IndexR] = QtCore.QPointF(
                background[self.IndexR].x(),
                R.top() + R.height() / 2)

            polygon[self.IndexB] = QtCore.QPointF(polygon[self.IndexB].x(),
                                                  R.bottom() - 4)
            polygon[self.IndexL] = QtCore.QPointF(polygon[self.IndexL].x(),
                                                  R.top() + R.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(polygon[self.IndexE].x(),
                                                  R.top() + R.height() / 2)
            polygon[self.IndexR] = QtCore.QPointF(polygon[self.IndexR].x(),
                                                  R.top() + R.height() / 2)

        elif self.mp_Handle == self.HandleBR:

            fromX = self.mp_Bound.right()
            fromY = self.mp_Bound.bottom()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, +4, snap)
            toY = snapF(toY, size, +4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            selection[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2,
                                                    selection[self.IndexT].y())
            selection[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2,
                                                    R.bottom())
            selection[self.IndexL] = QtCore.QPointF(
                selection[self.IndexL].x(),
                R.bottom() - R.height() / 2)
            selection[self.IndexE] = QtCore.QPointF(
                selection[self.IndexE].x(),
                R.bottom() - R.height() / 2)
            selection[self.IndexR] = QtCore.QPointF(
                R.right(),
                R.bottom() - R.height() / 2)

            background[self.IndexT] = QtCore.QPointF(
                R.right() - R.width() / 2, background[self.IndexT].y())
            background[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2,
                                                     R.bottom())
            background[self.IndexL] = QtCore.QPointF(
                background[self.IndexL].x(),
                R.bottom() - R.height() / 2)
            background[self.IndexE] = QtCore.QPointF(
                background[self.IndexE].x(),
                R.bottom() - R.height() / 2)
            background[self.IndexR] = QtCore.QPointF(
                R.right(),
                R.bottom() - R.height() / 2)

            polygon[self.IndexT] = QtCore.QPointF(R.right() - R.width() / 2,
                                                  polygon[self.IndexT].y())
            polygon[self.IndexB] = QtCore.QPointF(R.right() - R.width() / 2,
                                                  R.bottom() - 4)
            polygon[self.IndexL] = QtCore.QPointF(polygon[self.IndexL].x(),
                                                  R.bottom() - R.height() / 2)
            polygon[self.IndexE] = QtCore.QPointF(polygon[self.IndexE].x(),
                                                  R.bottom() - R.height() / 2)
            polygon[self.IndexR] = QtCore.QPointF(R.right() - 4,
                                                  R.bottom() - R.height() / 2)

        self.background.setGeometry(background)
        self.selection.setGeometry(selection)
        self.polygon.setGeometry(polygon)

        self.updateNode(selected=True,
                        handle=self.mp_Handle,
                        anchors=(self.mp_Data, D))
        self.updateTextPos(moved=moved)

    def setAsymmetric(self, asymmetric):
        """
        Set the asymmetric property for the predicate represented by this node.
        :type asymmetric: bool
        """
        meta = self.project.meta(self.type(), self.text())
        meta[K_ASYMMETRIC] = bool(asymmetric)
        self.project.setMeta(self.type(), self.text(), meta)

    def setFunctional(self, functional):
        """
        Set the functional property of the predicate represented by this node.
        :type functional: bool
        """
        meta = self.project.meta(self.type(), self.text())
        meta[K_FUNCTIONAL] = bool(functional)
        self.project.setMeta(self.type(), self.text(), meta)
        for node in self.project.predicates(self.type(), self.text()):
            node.updateNode(functional=functional, selected=node.isSelected())

    def setIdentity(self, identity):
        """
        Set the identity of the current node.
        :type identity: Identity
        """
        pass

    def setInverseFunctional(self, inverseFunctional):
        """
        Set the inverse functional property of the predicate represented by this node.
        :type inverseFunctional: bool
        """
        meta = self.project.meta(self.type(), self.text())
        meta[K_INVERSE_FUNCTIONAL] = bool(inverseFunctional)
        self.project.setMeta(self.type(), self.text(), meta)
        for node in self.project.predicates(self.type(), self.text()):
            node.updateNode(inverseFunctional=inverseFunctional,
                            selected=node.isSelected())

    def setIrreflexive(self, irreflexive):
        """
        Set the irreflexive property for the predicate represented by this node.
        :type irreflexive: bool
        """
        meta = self.project.meta(self.type(), self.text())
        meta[K_IRREFLEXIVE] = bool(irreflexive)
        self.project.setMeta(self.type(), self.text(), meta)

    def setReflexive(self, reflexive):
        """
        Set the reflexive property for the predicate represented by this node.
        :type reflexive: bool
        """
        meta = self.project.meta(self.type(), self.text())
        meta[K_REFLEXIVE] = bool(reflexive)
        self.project.setMeta(self.type(), self.text(), meta)

    def setSymmetric(self, symmetric):
        """
        Set the symmetric property for the predicate represented by this node.
        :type symmetric: bool
        """
        meta = self.project.meta(self.type(), self.text())
        meta[K_SYMMETRIC] = bool(symmetric)
        self.project.setMeta(self.type(), self.text(), meta)

    def setTransitive(self, transitive):
        """
        Set the transitive property for the predicate represented by this node.
        :type transitive: bool
        """
        meta = self.project.meta(self.type(), self.text())
        meta[K_TRANSITIVE] = bool(transitive)
        self.project.setMeta(self.type(), self.text(), meta)

    def setText(self, text):
        """
        Set the label text.
        :type text: str
        """
        self.label.setText(text)

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        self.label.setPos(pos)
        self.label.setAlignment(QtCore.Qt.AlignCenter)

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        for polygon in self.handles:
            path.addEllipse(polygon.geometry())
        return path

    def special(self):
        """
        Returns the special type of this node.
        :rtype: Special
        """
        return Special.valueOf(self.text())

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        return self.label.text()

    def textPos(self):
        """
        Returns the current label position in item coordinates.
        :rtype: QPointF
        """
        return self.label.pos()

    def updateNode(self, functional=None, inverseFunctional=None, **kwargs):
        """
        Update the current node.
        :type functional: bool
        :type inverseFunctional: bool
        """
        if functional is None:
            functional = self.isFunctional()
        if inverseFunctional is None:
            inverseFunctional = self.isInverseFunctional()

        polygon = self.polygon.geometry()

        # FUNCTIONAL POLYGON (SHAPE)
        fpolygon = QtGui.QPainterPath()
        if functional and not inverseFunctional:
            path = QtGui.QPainterPath()
            path.addPolygon(
                QtGui.QPolygonF([
                    polygon[self.IndexL] + QtCore.QPointF(+5, 0),
                    polygon[self.IndexB] + QtCore.QPointF(0, -4),
                    polygon[self.IndexR] + QtCore.QPointF(-5, 0),
                    polygon[self.IndexT] + QtCore.QPointF(0, +4),
                    polygon[self.IndexL] + QtCore.QPointF(+5, 0),
                ]))
            fpolygon.addPolygon(polygon)
            fpolygon = fpolygon.subtracted(path)

        # INVERSE FUNCTIONAL POLYGON (SHAPE)
        ipolygon = QtGui.QPainterPath()
        if not functional and inverseFunctional:
            path = QtGui.QPainterPath()
            path.addPolygon(
                QtGui.QPolygonF([
                    polygon[self.IndexL] + QtCore.QPointF(+5, 0),
                    polygon[self.IndexB] + QtCore.QPointF(0, -4),
                    polygon[self.IndexR] + QtCore.QPointF(-5, 0),
                    polygon[self.IndexT] + QtCore.QPointF(0, +4),
                    polygon[self.IndexL] + QtCore.QPointF(+5, 0),
                ]))
            ipolygon.addPolygon(polygon)
            ipolygon = ipolygon.subtracted(path)

        # FUNCTIONAL + INVERSE FUNCTIONAL POLYGONS (SHAPE)
        if functional and inverseFunctional:
            path = QtGui.QPainterPath()
            path.addPolygon(
                QtGui.QPolygonF([
                    polygon[self.IndexL] + QtCore.QPointF(+5, 0),
                    polygon[self.IndexB] + QtCore.QPointF(0, -4),
                    polygon[self.IndexB],
                    polygon[self.IndexR],
                    polygon[self.IndexT],
                    polygon[self.IndexT] + QtCore.QPointF(0, +4),
                    polygon[self.IndexL] + QtCore.QPointF(+5, 0),
                ]))
            fpolygon.addPolygon(polygon)
            fpolygon = fpolygon.subtracted(path)
            path = QtGui.QPainterPath()
            path.addPolygon(
                QtGui.QPolygonF([
                    polygon[self.IndexL],
                    polygon[self.IndexB],
                    polygon[self.IndexB] + QtCore.QPointF(0, -4),
                    polygon[self.IndexR] + QtCore.QPointF(-5, 0),
                    polygon[self.IndexT] + QtCore.QPointF(0, +4),
                    polygon[self.IndexT],
                    polygon[self.IndexL],
                ]))
            ipolygon.addPolygon(polygon)
            ipolygon = ipolygon.subtracted(path)

        # FUNCTIONAL POLYGON (PEN + BRUSH)
        fpen = QtGui.QPen(QtCore.Qt.NoPen)
        fbrush = QtGui.QBrush(QtCore.Qt.NoBrush)
        if functional:
            fpen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1,
                              QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                              QtCore.Qt.RoundJoin)
            fbrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))

        # INVERSE FUNCTIONAL POLYGON (PEN + BRUSH)
        ipen = QtGui.QPen(QtCore.Qt.NoPen)
        ibrush = QtGui.QBrush(QtCore.Qt.NoBrush)
        if inverseFunctional:
            ipen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1,
                              QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                              QtCore.Qt.RoundJoin)
            ibrush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 255))

        self.fpolygon.setPen(fpen)
        self.fpolygon.setBrush(fbrush)
        self.fpolygon.setGeometry(fpolygon)
        self.ipolygon.setPen(ipen)
        self.ipolygon.setBrush(ibrush)
        self.ipolygon.setGeometry(ipolygon)

        # SELECTION + BACKGROUND + HANDLES + ANCHORS + CACHE REFRESH
        super().updateNode(**kwargs)

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        self.label.updatePos(*args, **kwargs)

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        polygon = self.polygon.geometry()
        return polygon[self.IndexR].x() - polygon[self.IndexL].x()

    def __repr__(self):
        """
        Returns repr(self).
        """
        return '{0}:{1}:{2}'.format(self.__class__.__name__, self.text(),
                                    self.id)
Exemple #18
0
class AttributeNode(AbstractNode):
    """
    This class implements the 'Attribute' node.
    """
    DefaultBrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1,
                            QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                            QtCore.Qt.RoundJoin)
    Identities = {Identity.Attribute}
    Type = Item.AttributeNode

    def __init__(self,
                 width=20,
                 height=20,
                 brush=None,
                 remaining_characters='attribute',
                 **kwargs):
        """
        Initialize the node.
        :type width: int
        :type height: int
        :type brush: QBrush
        """
        super().__init__(**kwargs)
        brush = brush or AttributeNode.DefaultBrush
        pen = AttributeNode.DefaultPen
        self.fpolygon = Polygon(QtGui.QPainterPath())
        self.background = Polygon(QtCore.QRectF(-14, -14, 28, 28))
        self.selection = Polygon(QtCore.QRectF(-14, -14, 28, 28))
        self.polygon = Polygon(QtCore.QRectF(-10, -10, 20, 20), brush, pen)

        self.remaining_characters = remaining_characters

        self.label = NodeLabel(
            template='attribute',
            pos=lambda: self.center() - QtCore.QPointF(0, 22),
            parent=self,
            editable=True)
        self.label.setAlignment(QtCore.Qt.AlignCenter)

    #############################################
    #   INTERFACE
    #################################

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QRectF
        """
        return self.selection.geometry()

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        node = diagram.factory.create(
            self.type(), **{
                'id': self.id,
                'brush': self.brush(),
                'height': self.height(),
                'width': self.width(),
                'remaining_characters': self.remaining_characters,
            })
        node.setPos(self.pos())
        node.setText(self.text())
        node.setTextPos(node.mapFromScene(self.mapToScene(self.textPos())))
        return node

    def definition(self):
        """
        Returns the list of nodes which contribute to the definition of this very node.
        :rtype: set
        """
        f1 = lambda x: x.type() is Item.InputEdge
        f2 = lambda x: x.type(
        ) in {Item.DomainRestrictionNode, Item.RangeRestrictionNode}
        return set(self.outgoingNodes(filter_on_edges=f1, filter_on_nodes=f2))

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        return self.polygon.geometry().height()

    def identity(self):
        """
        Returns the identity of the current node.
        :rtype: Identity
        """
        return Identity.Attribute

    def isFunctional(self):
        """
        Returns True if the predicate represented by this node is functional, else False.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(),
                                     self.text())[K_FUNCTIONAL]  #\
            #and \
            #self.project.profile.type() is not OWLProfile.OWL2QL

        except (AttributeError, KeyError):
            return False

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawEllipse(self.selection.geometry())
        # SYNTAX VALIDATION
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawEllipse(self.background.geometry())
        # ITEM SHAPE
        painter.setPen(self.polygon.pen())
        painter.setBrush(self.polygon.brush())
        painter.drawEllipse(self.polygon.geometry())
        # FUNCTIONALITY
        painter.setPen(self.fpolygon.pen())
        painter.setBrush(self.fpolygon.brush())
        painter.drawPath(self.fpolygon.geometry())

    def painterPath(self):
        """
        Returns the current shape as QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addEllipse(self.polygon.geometry())
        return path

    def setFunctional(self, functional):
        """
        Set the functional property of the predicate represented by this node.
        :type functional: bool
        """
        meta = self.project.meta(self.type(), self.text())
        meta[K_FUNCTIONAL] = bool(functional)
        self.project.setMeta(self.type(), self.text(), meta)
        for node in self.project.predicates(self.type(), self.text()):
            node.updateNode(functional=functional, selected=node.isSelected())

    def setIdentity(self, identity):
        """
        Set the identity of the current node.
        :type identity: Identity
        """
        pass

    def setText(self, text):
        """
        Set the label text.
        :type text: str
        """
        self.label.setText(text)
        self.label.setAlignment(QtCore.Qt.AlignCenter)

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        self.label.setPos(pos)

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addEllipse(self.polygon.geometry())
        return path

    def special(self):
        """
        Returns the special type of this node.
        :rtype: Special
        """
        return Special.valueOf(self.text())

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        return self.label.text()

    def textPos(self):
        """
        Returns the current label position in item coordinates.
        :rtype: QPointF
        """
        return self.label.pos()

    def updateNode(self, functional=None, **kwargs):
        """
        Update the current node.
        :type functional: bool
        """
        if functional is None:
            functional = self.isFunctional()

        # FUNCTIONAL POLYGON (SHAPE)
        path1 = QtGui.QPainterPath()
        path1.addEllipse(self.polygon.geometry())
        path2 = QtGui.QPainterPath()
        path2.addEllipse(QtCore.QRectF(-7, -7, 14, 14))
        self.fpolygon.setGeometry(path1.subtracted(path2))

        # FUNCTIONAL POLYGON (PEN & BRUSH)
        pen = QtGui.QPen(QtCore.Qt.NoPen)
        brush = QtGui.QBrush(QtCore.Qt.NoBrush)
        if functional:
            pen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1,
                             QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                             QtCore.Qt.RoundJoin)
            brush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
        self.fpolygon.setPen(pen)
        self.fpolygon.setBrush(brush)

        # SELECTION + BACKGROUND + CACHE REFRESH
        super().updateNode(**kwargs)

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        self.label.updatePos(*args, **kwargs)

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        return self.polygon.geometry().width()

    def __repr__(self):
        """
        Returns repr(self).
        """
        return '{0}:{1}:{2}'.format(self.__class__.__name__, self.text(),
                                    self.id)
Exemple #19
0
class EquivalenceEdge(AxiomEdge):
    """
    This class implements the 'Equivalence' edge.
    """
    Type = Item.EquivalenceEdge

    def __init__(self, **kwargs):
        """
        Initialize the edge.
        """
        super().__init__(**kwargs)
        self.tail = Polygon(QtGui.QPolygonF())

    #############################################
    #   INTERFACE
    #################################

    def boundingRect(self):
        """
        Returns the shape bounding rect.
        :rtype: QRectF
        """
        path = QtGui.QPainterPath()
        path.addPath(self.selection.geometry())
        path.addPolygon(self.head.geometry())
        path.addPolygon(self.tail.geometry())
        for polygon in self.handles:
            path.addEllipse(polygon.geometry())
        for polygon in self.anchors.values():
            path.addEllipse(polygon.geometry())
        return path.controlPointRect()

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        return diagram.factory.create(
            self.type(), **{
                'id': self.id,
                'source': self.source,
                'target': self.target,
                'breakpoints': self.breakpoints[:],
            })

    @staticmethod
    def createHead(p1, angle, size):
        """
        Create the head polygon.
        :type p1: QPointF
        :type angle: float
        :type size: int
        :rtype: QPolygonF
        """
        rad = radians(angle)
        p2 = p1 - QtCore.QPointF(
            sin(rad + M_PI / 3.0) * size,
            cos(rad + M_PI / 3.0) * size)
        p3 = p1 - QtCore.QPointF(
            sin(rad + M_PI - M_PI / 3.0) * size,
            cos(rad + M_PI - M_PI / 3.0) * size)
        return QtGui.QPolygonF([p1, p2, p3])

    @staticmethod
    def createTail(p1, angle, size):
        """
        Create the tail polygon.
        :type p1: QPointF
        :type angle: float
        :type size: int
        :rtype: QPolygonF
        """
        rad = radians(angle)
        p2 = p1 + QtCore.QPointF(
            sin(rad + M_PI / 3.0) * size,
            cos(rad + M_PI / 3.0) * size)
        p3 = p1 + QtCore.QPointF(
            sin(rad + M_PI - M_PI / 3.0) * size,
            cos(rad + M_PI - M_PI / 3.0) * size)
        return QtGui.QPolygonF([p1, p2, p3])

    def paint(self, painter, option, widget=None):
        """
        Paint the edge in the diagram scene.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.fillPath(self.selection.geometry(), self.selection.brush())
        # EDGE LINE
        painter.setPen(self.path.pen())
        painter.drawPath(self.path.geometry())
        # HEAD POLYGON
        painter.setPen(self.head.pen())
        painter.setBrush(self.head.brush())
        painter.drawPolygon(self.head.geometry())
        # TAIL POLYGON
        painter.setPen(self.tail.pen())
        painter.setBrush(self.tail.brush())
        painter.drawPolygon(self.tail.geometry())
        # BREAKPOINTS
        for polygon in self.handles:
            painter.setPen(polygon.pen())
            painter.setBrush(polygon.brush())
            painter.drawEllipse(polygon.geometry())
        # ANCHOR POINTS
        for polygon in self.anchors.values():
            painter.setPen(polygon.pen())
            painter.setBrush(polygon.brush())
            painter.drawEllipse(polygon.geometry())

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPath(self.path.geometry())
        path.addPolygon(self.head.geometry())
        path.addPolygon(self.tail.geometry())
        return path

    def setText(self, text):
        """
        Set the label text.
        :type text: str
        """
        pass

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        pass

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPath(self.selection.geometry())
        path.addPolygon(self.head.geometry())
        path.addPolygon(self.tail.geometry())
        if self.isSelected():
            for polygon in self.handles:
                path.addEllipse(polygon.geometry())
            for polygon in self.anchors.values():
                path.addEllipse(polygon.geometry())
        return path

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        pass

    def textPos(self):
        """
        Returns the current label position.
        :rtype: QPointF
        """
        pass

    def updateEdge(self,
                   selected=None,
                   visible=None,
                   breakpoint=None,
                   anchor=None,
                   target=None,
                   **kwargs):
        """
        Update the current edge.
        :type selected: bool
        :type visible: bool
        :type breakpoint: int
        :type anchor: AbstractNode
        :type target: QtCore.QPointF
        """
        if visible is None:
            visible = self.canDraw()

        sourceNode = self.source
        targetNode = self.target
        sourcePos = sourceNode.anchor(self)
        targetPos = target
        if targetPos is None:
            targetPos = targetNode.anchor(self)

        self.prepareGeometryChange()

        ##########################################
        # PATH, SELECTION, HEAD, TAIL (GEOMETRY)
        #################################

        collection = self.createPath(sourceNode, targetNode, [sourcePos] +
                                     self.breakpoints + [targetPos])

        selection = QtGui.QPainterPath()
        path = QtGui.QPainterPath()
        head = QtGui.QPolygonF()
        tail = QtGui.QPolygonF()

        if len(collection) == 1:
            subpath = collection[0]
            p1 = sourceNode.intersection(subpath)
            p2 = targetNode.intersection(
                subpath) if targetNode else subpath.p2()
            if p1 is not None and p2 is not None:
                path.moveTo(p1)
                path.lineTo(p2)
                selection.addPolygon(createArea(p1, p2, subpath.angle(), 8))
                head = self.createHead(p2, subpath.angle(), 12)
                tail = self.createTail(p1, subpath.angle(), 12)
        elif len(collection) > 1:
            subpath1 = collection[0]
            subpathN = collection[-1]
            p11 = sourceNode.intersection(subpath1)
            p22 = targetNode.intersection(subpathN)
            if p11 and p22:
                p12 = subpath1.p2()
                p21 = subpathN.p1()
                path.moveTo(p11)
                path.lineTo(p12)
                selection.addPolygon(createArea(p11, p12, subpath1.angle(), 8))
                for subpath in collection[1:-1]:
                    p1 = subpath.p1()
                    p2 = subpath.p2()
                    path.moveTo(p1)
                    path.lineTo(p2)
                    selection.addPolygon(createArea(p1, p2, subpath.angle(),
                                                    8))
                path.moveTo(p21)
                path.lineTo(p22)
                selection.addPolygon(createArea(p21, p22, subpathN.angle(), 8))
                head = self.createHead(p22, subpathN.angle(), 12)
                tail = self.createTail(p11, subpath1.angle(), 12)

        self.selection.setGeometry(selection)
        self.path.setGeometry(path)
        self.head.setGeometry(head)
        self.tail.setGeometry(tail)

        ##########################################
        # PATH, HEAD, TAIL (BRUSH)
        #################################

        headBrush = QtGui.QBrush(QtCore.Qt.NoBrush)
        headPen = QtGui.QPen(QtCore.Qt.NoPen)
        pathPen = QtGui.QPen(QtCore.Qt.NoPen)
        tailBrush = QtGui.QBrush(QtCore.Qt.NoBrush)
        tailPen = QtGui.QPen(QtCore.Qt.NoPen)

        if visible:
            headBrush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 255))
            headPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1,
                                 QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                                 QtCore.Qt.RoundJoin)
            pathPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1,
                                 QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                                 QtCore.Qt.RoundJoin)
            tailBrush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 255))
            tailPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.1,
                                 QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                                 QtCore.Qt.RoundJoin)

        self.head.setBrush(headBrush)
        self.head.setPen(headPen)
        self.path.setPen(pathPen)
        self.tail.setBrush(tailBrush)
        self.tail.setPen(tailPen)

        super().updateEdge(selected, visible, breakpoint, anchor, **kwargs)
Exemple #20
0
class LiteralNode(AbstractResizableNode):
    """
    This class implements the 'Individual' node.
    """
    IndexLT = 0
    IndexLB = 1
    IndexBL = 2
    IndexBR = 3
    IndexRB = 4
    IndexRT = 5
    IndexTR = 6
    IndexTL = 7
    IndexEE = 8

    DefaultBrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.0,
                            QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                            QtCore.Qt.RoundJoin)
    Identities = {Identity.Value}
    Type = Item.LiteralNode

    def __init__(self,
                 literal=None,
                 width=60,
                 height=60,
                 brush=None,
                 **kwargs):
        """
        Initialize the node.
        :type width: int
        :type height: int
        :type brush: QBrush
        """
        super().__init__(**kwargs)

        w = max(width, 60)
        h = max(height, 60)
        brush = brush or LiteralNode.DefaultBrush
        pen = LiteralNode.DefaultPen

        createPolygon = lambda x, y: QtGui.QPolygonF([
            QtCore.QPointF(-(x / 2), -((y / (1 + math.sqrt(2))) / 2)),
            QtCore.QPointF(-(x / 2), +((y / (1 + math.sqrt(2))) / 2)),
            QtCore.QPointF(-((x / (1 + math.sqrt(2))) / 2), +(y / 2)),
            QtCore.QPointF(+((x / (1 + math.sqrt(2))) / 2), +(y / 2)),
            QtCore.QPointF(+(x / 2), +((y / (1 + math.sqrt(2))) / 2)),
            QtCore.QPointF(+(x / 2), -((y / (1 + math.sqrt(2))) / 2)),
            QtCore.QPointF(+((x / (1 + math.sqrt(2))) / 2), -(y / 2)),
            QtCore.QPointF(-((x / (1 + math.sqrt(2))) / 2), -(y / 2)),
            QtCore.QPointF(-(x / 2), -((y / (1 + math.sqrt(2))) / 2)),
        ])

        self.background = Polygon(createPolygon(w + 8, h + 8))
        self.selection = Polygon(createPolygon(w + 8, h + 8))
        self.polygon = Polygon(createPolygon(w, h), brush, pen)

        self._literal = literal

        #self.label = NodeLabel(template='Empty', pos=self.center, parent=self, editable=True)
        #self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.updateNode()
        #self.updateTextPos()

    @property
    def datatype(self):
        """
        Returns the datatype associated with this node.
        :rtype: IRI
        """
        if self._literal and self._literal.datatype:
            return self._literal.datatype
        else:
            return OWL2Datatype.PlainLiteral.value

    @property
    def lexicalForm(self):
        """
        Returns the lexical form of the literal associated with this node.
        :rtype: str
        """
        if self._literal:
            return self._literal.lexicalForm
        return None

    @property
    def language(self):
        if self._literal:
            return self._literal.language
        return None

    @property
    def literal(self):
        '''
        :rtype: Literal
        '''
        return self._literal

    @literal.setter
    def literal(self, literal):
        '''
        :type literal:Literal
        '''
        self._literal = literal
        if self.diagram:
            self.doUpdateNodeLabel()
        self.sgnNodeModified.emit()

    def initialLabelPosition(self):
        return self.center()

    #############################################
    #   SLOTS
    #################################
    @QtCore.pyqtSlot()
    def doUpdateNodeLabel(self):
        if self.label and not self.labelString == str(self.literal):
            self.labelString = str(self.literal)
            labelPos = lambda: self.label.pos()
            self.label.diagram.removeItem(self.label)
            self.label = NodeLabel(template=self.labelString,
                                   pos=labelPos,
                                   parent=self,
                                   editable=True)
            self.diagram.sgnUpdated.emit()
        else:
            self.labelString = str(self.literal)
            self.label = NodeLabel(template=self.labelString,
                                   pos=lambda: self.initialLabelPosition(),
                                   parent=self,
                                   editable=True)
            self.diagram.sgnUpdated.emit()

    #############################################
    #   INTERFACE
    #################################
    def mouseDoubleClickEvent(self, mouseEvent):
        """
        Executed when the mouse is double clicked on the text item.
        :type mouseEvent: QGraphicsSceneMouseEvent
        """
        self.session.doOpenLiteralDialog(self)
        mouseEvent.accept()

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QtCore.QRectF
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.selection.geometry())
        return path.boundingRect()

    @staticmethod
    def compose(value, datatype):
        """
        Compose the value string.
        :type value: str
        :type datatype: Datatype
        :return: str
        """
        return '"{0}"^^{1}'.format(value.strip('"'), datatype.value)

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        node = diagram.factory.create(
            self.type(), **{
                'id': self.id,
                'brush': self.brush(),
                'height': self.height(),
                'width': self.width(),
                'literal': self._literal,
            })
        node.setPos(self.pos())
        node.literal = self._literal
        node.setTextPos(node.mapFromScene(self.mapToScene(self.textPos())))
        return node

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        polygon = self.polygon.geometry()

        # return polygon[self.IndexTR].y() - polygon[self.IndexBR].y()
        return polygon[self.IndexBR].y() - polygon[self.IndexTR].y()

    def identity(self):
        """
        Returns the identity of the current node.
        :rtype: Identity
        """
        return Identity.Value

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawPolygon(self.selection.geometry())
        # SYNTAX VALIDATION
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawPolygon(self.background.geometry())
        # ITEM SHAPE
        painter.setPen(self.polygon.pen())
        painter.setBrush(self.polygon.brush())
        painter.drawPolygon(self.polygon.geometry())
        # RESIZE HANDLES
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        for polygon in self.handles:
            painter.setPen(polygon.pen())
            painter.setBrush(polygon.brush())
            painter.drawEllipse(polygon.geometry())

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        return path

    def resize(self, mousePos):
        """
        Handle the interactive resize of the shape.
        :type mousePos: QtCore.QPointF
        """
        snap = self.session.action('toggle_grid').isChecked()
        size = self.diagram.GridSize
        moved = self.label.isMoved()

        background = self.background.geometry()
        selection = self.selection.geometry()
        polygon = self.polygon.geometry()

        R = QtCore.QRectF(self.boundingRect())
        D = QtCore.QPointF(0, 0)

        mbrh = 68
        mbrw = 68

        self.prepareGeometryChange()

        if self.mp_Handle == self.HandleTL:

            fromX = self.mp_Bound.left()
            fromY = self.mp_Bound.top()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, -4, snap)
            toY = snapF(toY, size, -4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            newSideY = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newSideX = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSideY / 2
            newLeftRightTopY = (R.y() + R.height() / 2) - newSideY / 2
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSideX / 2
            newTopBottomRightX = (R.x() + R.width() / 2) + newSideX / 2

            selection[self.IndexLT] = QtCore.QPointF(R.left(),
                                                     newLeftRightTopY)
            selection[self.IndexLB] = QtCore.QPointF(R.left(),
                                                     newLeftRightBottomY)
            selection[self.IndexRT] = QtCore.QPointF(R.right(),
                                                     newLeftRightTopY)
            selection[self.IndexRB] = QtCore.QPointF(R.right(),
                                                     newLeftRightBottomY)
            selection[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                     R.top())
            selection[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                     R.top())
            selection[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                     R.bottom())
            selection[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                     R.bottom())
            selection[self.IndexEE] = QtCore.QPointF(R.left(),
                                                     newLeftRightTopY)

            background[self.IndexLT] = QtCore.QPointF(R.left(),
                                                      newLeftRightTopY)
            background[self.IndexLB] = QtCore.QPointF(R.left(),
                                                      newLeftRightBottomY)
            background[self.IndexRT] = QtCore.QPointF(R.right(),
                                                      newLeftRightTopY)
            background[self.IndexRB] = QtCore.QPointF(R.right(),
                                                      newLeftRightBottomY)
            background[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                      R.top())
            background[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                      R.top())
            background[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                      R.bottom())
            background[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                      R.bottom())
            background[self.IndexEE] = QtCore.QPointF(R.left(),
                                                      newLeftRightTopY)

            polygon[self.IndexLT] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightTopY)
            polygon[self.IndexLB] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightBottomY)
            polygon[self.IndexRT] = QtCore.QPointF(R.right() - 4,
                                                   newLeftRightTopY)
            polygon[self.IndexRB] = QtCore.QPointF(R.right() - 4,
                                                   newLeftRightBottomY)
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                   R.top() + 4)
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                   R.top() + 4)
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                   R.bottom() - 4)
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                   R.bottom() - 4)
            polygon[self.IndexEE] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightTopY)

        elif self.mp_Handle == self.HandleTM:

            fromY = self.mp_Bound.top()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toY = snapF(toY, size, -4, snap)
            D.setY(toY - fromY)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            newSide = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSide / 2
            newLeftRightTopY = (R.y() + R.height() / 2) - newSide / 2

            selection[self.IndexTL] = QtCore.QPointF(
                background[self.IndexTL].x(), R.top())
            selection[self.IndexTR] = QtCore.QPointF(
                background[self.IndexTR].x(), R.top())
            selection[self.IndexLB] = QtCore.QPointF(
                background[self.IndexLB].x(), newLeftRightBottomY)
            selection[self.IndexRB] = QtCore.QPointF(
                background[self.IndexRB].x(), newLeftRightBottomY)
            selection[self.IndexLT] = QtCore.QPointF(
                background[self.IndexLT].x(), newLeftRightTopY)
            selection[self.IndexRT] = QtCore.QPointF(
                background[self.IndexRT].x(), newLeftRightTopY)
            selection[self.IndexEE] = QtCore.QPointF(
                background[self.IndexEE].x(), newLeftRightTopY)

            background[self.IndexTL] = QtCore.QPointF(
                background[self.IndexTL].x(), R.top())
            background[self.IndexTR] = QtCore.QPointF(
                background[self.IndexTR].x(), R.top())
            background[self.IndexLB] = QtCore.QPointF(
                background[self.IndexLB].x(), newLeftRightBottomY)
            background[self.IndexRB] = QtCore.QPointF(
                background[self.IndexRB].x(), newLeftRightBottomY)
            background[self.IndexLT] = QtCore.QPointF(
                background[self.IndexLT].x(), newLeftRightTopY)
            background[self.IndexRT] = QtCore.QPointF(
                background[self.IndexRT].x(), newLeftRightTopY)
            background[self.IndexEE] = QtCore.QPointF(
                background[self.IndexEE].x(), newLeftRightTopY)

            polygon[self.IndexTL] = QtCore.QPointF(polygon[self.IndexTL].x(),
                                                   R.top() + 4)
            polygon[self.IndexTR] = QtCore.QPointF(polygon[self.IndexTR].x(),
                                                   R.top() + 4)
            polygon[self.IndexLB] = QtCore.QPointF(polygon[self.IndexLB].x(),
                                                   newLeftRightBottomY)
            polygon[self.IndexRB] = QtCore.QPointF(polygon[self.IndexRB].x(),
                                                   newLeftRightBottomY)
            polygon[self.IndexLT] = QtCore.QPointF(polygon[self.IndexLT].x(),
                                                   newLeftRightTopY)
            polygon[self.IndexRT] = QtCore.QPointF(polygon[self.IndexRT].x(),
                                                   newLeftRightTopY)
            polygon[self.IndexEE] = QtCore.QPointF(polygon[self.IndexEE].x(),
                                                   newLeftRightTopY)

        elif self.mp_Handle == self.HandleTR:

            fromX = self.mp_Bound.right()
            fromY = self.mp_Bound.top()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, +4, snap)
            toY = snapF(toY, size, -4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            newSideY = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newSideX = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSideY / 2
            newLeftRightTopY = (R.y() + R.height() / 2) - newSideY / 2
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSideX / 2
            newTopBottomRightX = (R.x() + R.width() / 2) + newSideX / 2

            selection[self.IndexLT] = QtCore.QPointF(R.left(),
                                                     newLeftRightTopY)
            selection[self.IndexLB] = QtCore.QPointF(R.left(),
                                                     newLeftRightBottomY)
            selection[self.IndexRT] = QtCore.QPointF(R.right(),
                                                     newLeftRightTopY)
            selection[self.IndexRB] = QtCore.QPointF(R.right(),
                                                     newLeftRightBottomY)
            selection[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                     R.top())
            selection[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                     R.top())
            selection[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                     R.bottom())
            selection[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                     R.bottom())
            selection[self.IndexEE] = QtCore.QPointF(R.left(),
                                                     newLeftRightTopY)

            background[self.IndexLT] = QtCore.QPointF(R.left(),
                                                      newLeftRightTopY)
            background[self.IndexLB] = QtCore.QPointF(R.left(),
                                                      newLeftRightBottomY)
            background[self.IndexRT] = QtCore.QPointF(R.right(),
                                                      newLeftRightTopY)
            background[self.IndexRB] = QtCore.QPointF(R.right(),
                                                      newLeftRightBottomY)
            background[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                      R.top())
            background[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                      R.top())
            background[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                      R.bottom())
            background[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                      R.bottom())
            background[self.IndexEE] = QtCore.QPointF(R.left(),
                                                      newLeftRightTopY)

            polygon[self.IndexLT] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightTopY)
            polygon[self.IndexLB] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightBottomY)
            polygon[self.IndexRT] = QtCore.QPointF(R.right() - 4,
                                                   newLeftRightTopY)
            polygon[self.IndexRB] = QtCore.QPointF(R.right() - 4,
                                                   newLeftRightBottomY)
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                   R.top() + 4)
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                   R.top() + 4)
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                   R.bottom() - 4)
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                   R.bottom() - 4)
            polygon[self.IndexEE] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightTopY)

        elif self.mp_Handle == self.HandleML:

            fromX = self.mp_Bound.left()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toX = snapF(toX, size, -4, snap)
            D.setX(toX - fromX)
            R.setLeft(toX)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())

            newSide = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSide / 2
            newTopBottomRightX = (R.x() + R.width() / 2) + newSide / 2

            selection[self.IndexLT] = QtCore.QPointF(
                R.left(), selection[self.IndexLT].y())
            selection[self.IndexLB] = QtCore.QPointF(
                R.left(), selection[self.IndexLB].y())
            selection[self.IndexEE] = QtCore.QPointF(
                R.left(), selection[self.IndexEE].y())
            selection[self.IndexTL] = QtCore.QPointF(
                newTopBottomLeftX, selection[self.IndexTL].y())
            selection[self.IndexTR] = QtCore.QPointF(
                newTopBottomRightX, selection[self.IndexTR].y())
            selection[self.IndexBL] = QtCore.QPointF(
                newTopBottomLeftX, selection[self.IndexBL].y())
            selection[self.IndexBR] = QtCore.QPointF(
                newTopBottomRightX, selection[self.IndexBR].y())

            background[self.IndexLT] = QtCore.QPointF(
                R.left(), background[self.IndexLT].y())
            background[self.IndexLB] = QtCore.QPointF(
                R.left(), background[self.IndexLB].y())
            background[self.IndexEE] = QtCore.QPointF(
                R.left(), background[self.IndexEE].y())
            background[self.IndexTL] = QtCore.QPointF(
                newTopBottomLeftX, background[self.IndexTL].y())
            background[self.IndexTR] = QtCore.QPointF(
                newTopBottomRightX, background[self.IndexTR].y())
            background[self.IndexBL] = QtCore.QPointF(
                newTopBottomLeftX, background[self.IndexBL].y())
            background[self.IndexBR] = QtCore.QPointF(
                newTopBottomRightX, background[self.IndexBR].y())

            polygon[self.IndexLT] = QtCore.QPointF(R.left() + 4,
                                                   polygon[self.IndexLT].y())
            polygon[self.IndexLB] = QtCore.QPointF(R.left() + 4,
                                                   polygon[self.IndexLB].y())
            polygon[self.IndexEE] = QtCore.QPointF(R.left() + 4,
                                                   polygon[self.IndexEE].y())
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                   polygon[self.IndexTL].y())
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                   polygon[self.IndexTR].y())
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                   polygon[self.IndexBL].y())
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                   polygon[self.IndexBR].y())

        elif self.mp_Handle == self.HandleMR:

            fromX = self.mp_Bound.right()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toX = snapF(toX, size, +4, snap)
            D.setX(toX - fromX)
            R.setRight(toX)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())

            newSide = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newTopBottomRightX = (R.x() + R.width() / 2) + newSide / 2
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSide / 2

            selection[self.IndexRT] = QtCore.QPointF(
                R.right(), selection[self.IndexRT].y())
            selection[self.IndexRB] = QtCore.QPointF(
                R.right(), selection[self.IndexRB].y())
            selection[self.IndexTL] = QtCore.QPointF(
                newTopBottomLeftX, selection[self.IndexTL].y())
            selection[self.IndexTR] = QtCore.QPointF(
                newTopBottomRightX, selection[self.IndexTR].y())
            selection[self.IndexBL] = QtCore.QPointF(
                newTopBottomLeftX, selection[self.IndexBL].y())
            selection[self.IndexBR] = QtCore.QPointF(
                newTopBottomRightX, selection[self.IndexBR].y())

            background[self.IndexRT] = QtCore.QPointF(
                R.right(), background[self.IndexRT].y())
            background[self.IndexRB] = QtCore.QPointF(
                R.right(), background[self.IndexRB].y())
            background[self.IndexTL] = QtCore.QPointF(
                newTopBottomLeftX, background[self.IndexTL].y())
            background[self.IndexTR] = QtCore.QPointF(
                newTopBottomRightX, background[self.IndexTR].y())
            background[self.IndexBL] = QtCore.QPointF(
                newTopBottomLeftX, background[self.IndexBL].y())
            background[self.IndexBR] = QtCore.QPointF(
                newTopBottomRightX, background[self.IndexBR].y())

            polygon[self.IndexRT] = QtCore.QPointF(R.right() - 4,
                                                   polygon[self.IndexRT].y())
            polygon[self.IndexRB] = QtCore.QPointF(R.right() - 4,
                                                   polygon[self.IndexRB].y())
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                   polygon[self.IndexTL].y())
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                   polygon[self.IndexTR].y())
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                   polygon[self.IndexBL].y())
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                   polygon[self.IndexBR].y())

        elif self.mp_Handle == self.HandleBL:

            fromX = self.mp_Bound.left()
            fromY = self.mp_Bound.bottom()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, -4, snap)
            toY = snapF(toY, size, +4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            newSideY = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newSideX = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSideY / 2
            newLeftRightTopY = (R.y() + R.height() / 2) - newSideY / 2
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSideX / 2
            newTopBottomRightX = (R.x() + R.width() / 2) + newSideX / 2

            selection[self.IndexLT] = QtCore.QPointF(R.left(),
                                                     newLeftRightTopY)
            selection[self.IndexLB] = QtCore.QPointF(R.left(),
                                                     newLeftRightBottomY)
            selection[self.IndexRT] = QtCore.QPointF(R.right(),
                                                     newLeftRightTopY)
            selection[self.IndexRB] = QtCore.QPointF(R.right(),
                                                     newLeftRightBottomY)
            selection[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                     R.top())
            selection[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                     R.top())
            selection[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                     R.bottom())
            selection[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                     R.bottom())
            selection[self.IndexEE] = QtCore.QPointF(R.left(),
                                                     newLeftRightTopY)

            background[self.IndexLT] = QtCore.QPointF(R.left(),
                                                      newLeftRightTopY)
            background[self.IndexLB] = QtCore.QPointF(R.left(),
                                                      newLeftRightBottomY)
            background[self.IndexRT] = QtCore.QPointF(R.right(),
                                                      newLeftRightTopY)
            background[self.IndexRB] = QtCore.QPointF(R.right(),
                                                      newLeftRightBottomY)
            background[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                      R.top())
            background[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                      R.top())
            background[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                      R.bottom())
            background[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                      R.bottom())
            background[self.IndexEE] = QtCore.QPointF(R.left(),
                                                      newLeftRightTopY)

            polygon[self.IndexLT] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightTopY)
            polygon[self.IndexLB] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightBottomY)
            polygon[self.IndexRT] = QtCore.QPointF(R.right() - 4,
                                                   newLeftRightTopY)
            polygon[self.IndexRB] = QtCore.QPointF(R.right() - 4,
                                                   newLeftRightBottomY)
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                   R.top() + 4)
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                   R.top() + 4)
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                   R.bottom() - 4)
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                   R.bottom() - 4)
            polygon[self.IndexEE] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightTopY)

        elif self.mp_Handle == self.HandleBM:

            fromY = self.mp_Bound.bottom()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toY = snapF(toY, size, +4, snap)
            D.setY(toY - fromY)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            newSide = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightTopY = (R.y() + R.height() / 2) - newSide / 2
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSide / 2

            selection[self.IndexBL] = QtCore.QPointF(
                selection[self.IndexBL].x(), R.bottom())
            selection[self.IndexBR] = QtCore.QPointF(
                selection[self.IndexBR].x(), R.bottom())
            selection[self.IndexLB] = QtCore.QPointF(
                selection[self.IndexLB].x(), newLeftRightBottomY)
            selection[self.IndexRB] = QtCore.QPointF(
                selection[self.IndexRB].x(), newLeftRightBottomY)
            selection[self.IndexLT] = QtCore.QPointF(
                selection[self.IndexLT].x(), newLeftRightTopY)
            selection[self.IndexRT] = QtCore.QPointF(
                selection[self.IndexRT].x(), newLeftRightTopY)
            selection[self.IndexEE] = QtCore.QPointF(
                selection[self.IndexEE].x(), newLeftRightTopY)

            background[self.IndexBL] = QtCore.QPointF(
                background[self.IndexBL].x(), R.bottom())
            background[self.IndexBR] = QtCore.QPointF(
                background[self.IndexBR].x(), R.bottom())
            background[self.IndexLB] = QtCore.QPointF(
                background[self.IndexLB].x(), newLeftRightBottomY)
            background[self.IndexRB] = QtCore.QPointF(
                background[self.IndexRB].x(), newLeftRightBottomY)
            background[self.IndexLT] = QtCore.QPointF(
                background[self.IndexLT].x(), newLeftRightTopY)
            background[self.IndexRT] = QtCore.QPointF(
                background[self.IndexRT].x(), newLeftRightTopY)
            background[self.IndexEE] = QtCore.QPointF(
                background[self.IndexEE].x(), newLeftRightTopY)

            polygon[self.IndexBL] = QtCore.QPointF(polygon[self.IndexBL].x(),
                                                   R.bottom() - 4)
            polygon[self.IndexBR] = QtCore.QPointF(polygon[self.IndexBR].x(),
                                                   R.bottom() - 4)
            polygon[self.IndexLB] = QtCore.QPointF(polygon[self.IndexLB].x(),
                                                   newLeftRightBottomY)
            polygon[self.IndexRB] = QtCore.QPointF(polygon[self.IndexRB].x(),
                                                   newLeftRightBottomY)
            polygon[self.IndexLT] = QtCore.QPointF(polygon[self.IndexLT].x(),
                                                   newLeftRightTopY)
            polygon[self.IndexRT] = QtCore.QPointF(polygon[self.IndexRT].x(),
                                                   newLeftRightTopY)
            polygon[self.IndexEE] = QtCore.QPointF(polygon[self.IndexEE].x(),
                                                   newLeftRightTopY)

        elif self.mp_Handle == self.HandleBR:

            fromX = self.mp_Bound.right()
            fromY = self.mp_Bound.bottom()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, +4, snap)
            toY = snapF(toY, size, +4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            newSideY = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newSideX = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSideY / 2
            newLeftRightTopY = (R.y() + R.height() / 2) - newSideY / 2
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSideX / 2
            newTopBottomRightX = (R.x() + R.width() / 2) + newSideX / 2

            selection[self.IndexLT] = QtCore.QPointF(R.left(),
                                                     newLeftRightTopY)
            selection[self.IndexLB] = QtCore.QPointF(R.left(),
                                                     newLeftRightBottomY)
            selection[self.IndexRT] = QtCore.QPointF(R.right(),
                                                     newLeftRightTopY)
            selection[self.IndexRB] = QtCore.QPointF(R.right(),
                                                     newLeftRightBottomY)
            selection[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                     R.top())
            selection[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                     R.top())
            selection[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                     R.bottom())
            selection[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                     R.bottom())
            selection[self.IndexEE] = QtCore.QPointF(R.left(),
                                                     newLeftRightTopY)

            background[self.IndexLT] = QtCore.QPointF(R.left(),
                                                      newLeftRightTopY)
            background[self.IndexLB] = QtCore.QPointF(R.left(),
                                                      newLeftRightBottomY)
            background[self.IndexRT] = QtCore.QPointF(R.right(),
                                                      newLeftRightTopY)
            background[self.IndexRB] = QtCore.QPointF(R.right(),
                                                      newLeftRightBottomY)
            background[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                      R.top())
            background[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                      R.top())
            background[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                      R.bottom())
            background[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                      R.bottom())
            background[self.IndexEE] = QtCore.QPointF(R.left(),
                                                      newLeftRightTopY)

            polygon[self.IndexLT] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightTopY)
            polygon[self.IndexLB] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightBottomY)
            polygon[self.IndexRT] = QtCore.QPointF(R.right() - 4,
                                                   newLeftRightTopY)
            polygon[self.IndexRB] = QtCore.QPointF(R.right() - 4,
                                                   newLeftRightBottomY)
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX,
                                                   R.top() + 4)
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX,
                                                   R.top() + 4)
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX,
                                                   R.bottom() - 4)
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX,
                                                   R.bottom() - 4)
            polygon[self.IndexEE] = QtCore.QPointF(R.left() + 4,
                                                   newLeftRightTopY)

        self.background.setGeometry(background)
        self.selection.setGeometry(selection)
        self.polygon.setGeometry(polygon)

        self.updateNode(selected=True,
                        handle=self.mp_Handle,
                        anchors=(self.mp_Data, D))
        self.updateTextPos(moved=moved)

    def setIdentity(self, identity):
        """
        Set the identity of the current node.
        :type identity: Identity
        """
        pass

    def setText(self, text):
        """
        Set the label text: will additionally block label editing if a literal is being.
        :type text: str
        """
        self.label.setText(text)
        self.label.setAlignment(QtCore.Qt.AlignCenter)

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        self.label.setPos(pos)

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        for polygon in self.handles:
            path.addEllipse(polygon.geometry())
        return path

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        return self.label.text()

    def textPos(self):
        """
        Returns the current label position in item coordinates.
        :rtype: QPointF
        """
        return self.label.pos()

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        self.label.updatePos(*args, **kwargs)

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        polygon = self.polygon.geometry()
        return polygon[self.IndexRT].x() - polygon[self.IndexLT].x()

    def __repr__(self):
        """
        Returns repr(self).
        """
        return '{0}:{1}:{2}'.format(self.__class__.__name__, self.text(),
                                    self.id)
Exemple #21
0
class FacetNode(AbstractNode):
    """
    This class implements the 'Facet' node.
    """
    IndexTL = 0
    IndexTR = 1
    IndexBR = 2
    IndexBL = 3
    IndexEE = 4

    DefaultBrushA = QtGui.QBrush(QtGui.QColor(222, 222, 222, 255))
    DefaultBrushB = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPenA = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.0,
                             QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                             QtCore.Qt.RoundJoin)
    DefaultPenB = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.0,
                             QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
                             QtCore.Qt.RoundJoin)
    Identities = {Identity.Facet}
    Type = Item.FacetIRINode

    def __init__(self, facet=None, width=80, height=40, brush=None, **kwargs):
        """
        Initialize the node.
        :type width: int
        :type height: int
        :type brush: QBrush
        :type facet: Facet
        """
        super().__init__(**kwargs)
        self.background = Polygon(self.createPolygon(88, 48))
        self.selection = Polygon(self.createPolygon(88, 48))
        self.polygon = Polygon(self.createPolygon(80, 40))
        self.polygonA = Polygon(self.createPolygonA(80, 40),
                                FacetNode.DefaultBrushA, FacetNode.DefaultPenA)
        self.polygonB = Polygon(self.createPolygonA(80, 40),
                                FacetNode.DefaultBrushB, FacetNode.DefaultPenB)
        self._facet = facet

        self.labelA = NodeLabel('Empty',
                                pos=self.centerA,
                                editable=False,
                                movable=False,
                                parent=self)
        self.labelB = FacetQuotedLabel(template='"Empty"',
                                       movable=False,
                                       pos=self.centerB,
                                       parent=self)
        self.updateNode()
        self.updateTextPos()

    #############################################
    #   PROPERTIES
    #################################
    @property
    def datatype(self):
        """
        Returns the datatype this facet is restricting, or None if the node is isolated.
        :rtype: Datatype
        """
        f1 = lambda x: x.type() is Item.InputEdge
        f2 = lambda x: x.type() is Item.DatatypeRestrictionNode
        f3 = lambda x: x.type() is Item.ValueDomainNode
        outgoing = first(
            self.outgoingNodes(filter_on_edges=f1, filter_on_nodes=f2))
        if outgoing:
            incoming = first(
                outgoing.incomingNodes(filter_on_edges=f1, filter_on_nodes=f3))
            if incoming:
                return incoming.datatype
        return None

    @property
    def facet(self):
        '''
        :rtype: Facet
        '''
        return self._facet

    @facet.setter
    def facet(self, facet):
        '''
        :type facet:Facet
        '''
        self._facet = facet
        if self.diagram:
            self.doUpdateNodeLabel()
        self.sgnNodeModified.emit()

    #############################################
    #   SLOTS
    #################################
    @QtCore.pyqtSlot()
    def doUpdateNodeLabel(self):
        iri = self.facet.constrainingFacet
        prefixed = iri.manager.getShortestPrefixedForm(iri)
        if prefixed:
            self.labelA.setText(str(prefixed))
        else:
            self.labelA.setText('<{}>', str(iri))

        literal = self.facet.literal
        self.labelB.setText(str(literal))
        #self.updateNode()

    #############################################
    #   INTERFACE
    #################################
    def mouseDoubleClickEvent(self, mouseEvent):
        """
        Executed when the mouse is double clicked on the text item.
        :type mouseEvent: QGraphicsSceneMouseEvent
        """
        print()
        self.session.doOpenConstrainingFacetBuilder(self)
        mouseEvent.accept()

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QtCore.QRectF
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.selection.geometry())
        return path.boundingRect()

    def brushA(self):
        """
        Returns the brush used to paint the shape A of this node.
        :rtype: QtGui.QBrush
        """
        return self.polygonA.brush()

    def brushB(self):
        """
        Returns the brush used to paint the shape B of this node.
        :rtype: QtGui.QBrush
        """
        return self.polygonB.brush()

    def centerA(self):
        """
        Returns the center point of polygon A.
        :rtype: QPointF
        """
        return self.boundingRect().center() - QtCore.QPointF(0, 40 / 4)

    def centerB(self):
        """
        Returns the center point of polygon A.
        :rtype: QPointF
        """
        return self.boundingRect().center() + QtCore.QPointF(0, 40 / 4)

    @staticmethod
    def compose(facet, value):
        """
        Compose the restriction string.
        :type facet: Facet
        :type value: str
        :return: str
        """
        return '{0}^^"{1}"'.format(facet.value, value.strip().strip('"'))

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        node = diagram.factory.create(
            self.type(), **{
                'id': self.id,
                'height': self.height(),
                'width': self.width(),
                'facet': self.facet
            })
        node.setPos(self.pos())
        node.setText(self.text())
        node.updateNode()
        node.setTextPos(node.mapFromScene(self.mapToScene(self.textPos())))
        return node

    def definition(self):
        """
        Returns the list of nodes which contribute to the definition of this very node.
        :rtype: set
        """
        return set(
            self.incomingNodes(
                filter_on_edges=lambda x: x.type() is Item.InputEdge))

    @staticmethod
    def createPolygon(w, h):
        """
        Returns the initialized polygon according to the given width/height.
        :type w: int
        :type h: int
        :rtype: QtGui.QPolygonF
        """
        return QtGui.QPolygonF([
            QtCore.QPointF(-w / 2 + 10, -h / 2),
            QtCore.QPointF(+w / 2, -h / 2),
            QtCore.QPointF(+w / 2 - 10, +h / 2),
            QtCore.QPointF(-w / 2, +h / 2),
            QtCore.QPointF(-w / 2 + 10, -h / 2),
        ])

    @staticmethod
    def createPolygonA(w, h):
        """
        Returns the initialized top-half polygon according to the given width/height.
        :type w: int
        :type h: int
        :rtype: QtGui.QPolygonF
        """
        return QtGui.QPolygonF([
            QtCore.QPointF(-w / 2 + 10, -h / 2),
            QtCore.QPointF(+w / 2, -h / 2),
            QtCore.QPointF(+w / 2 - 10 / 2, 0),
            QtCore.QPointF(-w / 2 + 10 / 2, 0),
            QtCore.QPointF(-w / 2 + 10, -h / 2),
        ])

    @staticmethod
    def createPolygonB(w, h):
        """
        Returns the initialized bottom-half polygon according to the given width/height.
        :type w: int
        :type h: int
        :rtype: QtGui.QPolygonF
        """
        return QtGui.QPolygonF([
            QtCore.QPointF(-w / 2 + 10 / 2, 0),
            QtCore.QPointF(+w / 2 - 10 / 2, 0),
            QtCore.QPointF(+w / 2 - 10, +h / 2),
            QtCore.QPointF(-w / 2, +h / 2),
            QtCore.QPointF(-w / 2 + 10 / 2, 0),
        ])

    def geometryA(self):
        """
        Returns the geometry of the shape A of this node.
        :rtype: QtGui.QPolygonF
        """
        return self.polygonA.geometry()

    def geometryB(self):
        """
        Returns the geometry of the shape B of this node.
        :rtype: QtGui.QPolygonF
        """
        return self.polygonB.geometry()

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        polygonA = self.polygonA.geometry()
        polygonB = self.polygonB.geometry()
        return polygonA[self.IndexBL].y() - polygonB[self.IndexTL].y()

    def identity(self):
        """
        Returns the identity of the current node.
        :rtype: Identity
        """
        return Identity.Facet

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawPolygon(self.selection.geometry())
        # SYNTAX VALIDATION
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawPolygon(self.background.geometry())
        # SHAPE
        painter.setPen(self.polygonA.pen())
        painter.setBrush(self.polygonA.brush())
        painter.drawPolygon(self.polygonA.geometry())
        painter.setPen(self.polygonB.pen())
        painter.setBrush(self.polygonB.brush())
        painter.drawPolygon(self.polygonB.geometry())

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        return path

    def penA(self):
        """
        Returns the pen used to paint the shape A of this node.
        :rtype: QtGui.QPen
        """
        return self.polygonA.pen()

    def penB(self):
        """
        Returns the pen used to paint the shape B of this node.
        :rtype: QtGui.QPen
        """
        return self.polygonB.pen()

    def setIdentity(self, identity):
        """
        Set the identity of the current node.
        :type identity: Identity
        """
        pass

    def setText(self, text):
        """
        Set the label text.
        :type text: str
        """
        pass

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        pass

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        return path

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        if self.facet:
            return str(self.facet)
        return 'Facet'

    def textPos(self):
        """
        Returns the current label position in item coordinates.
        :rtype: QPointF
        """
        return self.boundingRect().center()

    def updateNode(self, *args, **kwargs):
        """
        Update the current node.
        """
        # POLYGONS + BACKGROUND + SELECTION (GEOMETRY)
        width = max(self.labelA.width() + 16, self.labelB.width() + 16, 80)
        self.background.setGeometry(self.createPolygon(width + 8, 48))
        self.selection.setGeometry(self.createPolygon(width + 8, 48))
        self.polygon.setGeometry(self.createPolygon(width, 40))
        self.polygonA.setGeometry(self.createPolygonA(width, 40))
        self.polygonB.setGeometry(self.createPolygonB(width, 40))
        self.updateTextPos()
        self.updateEdges()

        # SELECTION + BACKGROUND + CACHE REFRESH
        super().updateNode(**kwargs)

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        self.labelA.updatePos()
        self.labelB.updatePos()

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        polygonA = self.polygonA.geometry()
        polygonB = self.polygonB.geometry()
        return polygonA[self.IndexTR].x() - polygonB[self.IndexBL].x()
Exemple #22
0
class RestrictionNode(AbstractNode):
    """
    This is the base class for all the Restriction nodes.
    """
    __metaclass__ = ABCMeta

    DefaultBrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.0, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)

    def __init__(self, width=20, height=20, brush=None, **kwargs):
        """
        Initialize the node.
        :type width: int
        :type height: int
        :type brush: QBrush
        """
        super().__init__(**kwargs)
        brush = brush or RestrictionNode.DefaultBrush
        pen = RestrictionNode.DefaultPen
        self.background = Polygon(QtCore.QRectF(-14, -14, 28, 28))
        self.selection = Polygon(QtCore.QRectF(-14, -14, 28, 28))
        self.polygon = Polygon(QtCore.QRectF(-10, -10, 20, 20), brush, pen)
        self.label = NodeLabel(Restriction.Exists.toString(),
           pos=lambda: self.center() - QtCore.QPointF(0, 22),
           editable=False, parent=self)

    #############################################
    #   INTERFACE
    #################################

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QtCore.QRectF
        """
        return self.selection.geometry()

    def cardinality(self, *args):
        """
        Returns the cardinality of the node.
        :rtype: T <= int|dict
        """
        cardinality = {'min': None, 'max': None}
        match = RE_CARDINALITY.match(self.text())
        if match:
            if match.group('min') != '-':
                cardinality['min'] = int(match.group('min'))
            if match.group('max') != '-':
                cardinality['max'] = int(match.group('max'))
        if args:
            cardinality = {k:v for k, v in cardinality.items() if k in args}
            if len(cardinality) == 1:
                cardinality = first(cardinality.values())
        return cardinality

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        node = diagram.factory.create(self.type(), **{
            'id': self.id,
            'height': self.height(),
            'width': self.width()
        })
        node.setPos(self.pos())
        node.setText(self.text())
        node.setTextPos(node.mapFromScene(self.mapToScene(self.textPos())))
        return node

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        return self.polygon.geometry().height()

    def isRestrictionQualified(self):
        """
        Returna True if this node expresses a qualified restriction (exists R.C), False otherwise.
        :rtype: bool
        """
        f1 = lambda x: x.type() is Item.InputEdge
        f2 = lambda x: x.identity() in {Identity.Concept, Identity.Role}
        f3 = lambda x: x.identity() in {Identity.Attribute, Identity.ValueDomain}
        f4 = lambda x: x.identity() is Identity.Concept
        if self.restriction() in {Restriction.Cardinality, Restriction.Exists, Restriction.Forall}:
            # CHECK FOR ROLE QUALIFIED RESTRICTION
            collection = self.incomingNodes(filter_on_edges=f1, filter_on_nodes=f2)
            if len(collection) >= 2:
                node = first(collection, filter_on_item=f4)
                if node and Special.forValue(node.text()) is not Special.Top:
                    return True
            # CHECK FOR ATTRIBUTE QUALIFIED RESTRICTION
            return len(self.incomingNodes(filter_on_edges=f1, filter_on_nodes=f3)) >= 2
        return False

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawRect(self.selection.geometry())
        # SYNTAX VALIDATION
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawRect(self.background.geometry())
        # ITEM SHAPE
        painter.setPen(self.polygon.pen())
        painter.setBrush(self.polygon.brush())
        painter.drawRect(self.polygon.geometry())

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addRect(self.polygon.geometry())
        return path

    def restriction(self):
        """
        Returns the restriction type of the node.
        :rtype: Restriction
        """
        return Restriction.forLabel(self.text())

    def setText(self, text):
        """
        Set the label text.
        Will additionally parse the given value checking for a consistent restriction type.
        :type text: str
        """
        restriction = Restriction.forLabel(text)
        if not restriction:
            text = Restriction.Exists.toString()
        self.label.setText(text)

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        self.label.setPos(pos)

    def shape(self, *args, **kwargs):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addRect(self.polygon.geometry())
        return path

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        return self.label.text()

    def textPos(self):
        """
        Returns the current label position.
        :rtype: QPointF
        """
        return self.label.pos()

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        return self.polygon.geometry().width()

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        self.label.updatePos(*args, **kwargs)
Exemple #23
0
class IndividualNode(AbstractResizableNode):
    """
    This class implements the 'Individual' node.
    """

    IndexLT = 0
    IndexLB = 1
    IndexBL = 2
    IndexBR = 3
    IndexRB = 4
    IndexRT = 5
    IndexTR = 6
    IndexTL = 7
    IndexEE = 8

    DefaultBrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPen = QtGui.QPen(
        QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.0, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin
    )
    Identities = {Identity.Individual, Identity.Value}
    Type = Item.IndividualNode

    def __init__(self, width=60, height=60, brush=None, **kwargs):
        """
        Initialize the node.
        :type width: int
        :type height: int
        :type brush: QBrush
        """
        super().__init__(**kwargs)

        w = max(width, 60)
        h = max(height, 60)
        brush = brush or IndividualNode.DefaultBrush
        pen = IndividualNode.DefaultPen

        createPolygon = lambda x, y: QtGui.QPolygonF(
            [
                QtCore.QPointF(-(x / 2), -((y / (1 + math.sqrt(2))) / 2)),
                QtCore.QPointF(-(x / 2), +((y / (1 + math.sqrt(2))) / 2)),
                QtCore.QPointF(-((x / (1 + math.sqrt(2))) / 2), +(y / 2)),
                QtCore.QPointF(+((x / (1 + math.sqrt(2))) / 2), +(y / 2)),
                QtCore.QPointF(+(x / 2), +((y / (1 + math.sqrt(2))) / 2)),
                QtCore.QPointF(+(x / 2), -((y / (1 + math.sqrt(2))) / 2)),
                QtCore.QPointF(+((x / (1 + math.sqrt(2))) / 2), -(y / 2)),
                QtCore.QPointF(-((x / (1 + math.sqrt(2))) / 2), -(y / 2)),
                QtCore.QPointF(-(x / 2), -((y / (1 + math.sqrt(2))) / 2)),
            ]
        )

        self.background = Polygon(createPolygon(w + 8, h + 8))
        self.selection = Polygon(createPolygon(w + 8, h + 8))
        self.polygon = Polygon(createPolygon(w, h), brush, pen)
        self.label = NodeLabel(template="individual", pos=self.center, parent=self)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.updateNode()
        self.updateTextPos()

    #############################################
    #   PROPERTIES
    #################################

    @property
    def datatype(self):
        """
        Returns the datatype associated with this node.
        :rtype: Datatype
        """
        match = RE_VALUE.match(self.text())
        if match:
            return Datatype.forValue(match.group("datatype"))
        return None

    @property
    def value(self):
        """
        Returns the value value associated with this node.
        :rtype: str
        """
        match = RE_VALUE.match(self.text())
        if match:
            return match.group("value")
        return None

    #############################################
    #   INTERFACE
    #################################

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QtCore.QRectF
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.selection.geometry())
        return path.boundingRect()

    @staticmethod
    def compose(value, datatype):
        """
        Compose the value string.
        :type value: str
        :type datatype: Datatype
        :return: str
        """
        return '"{0}"^^{1}'.format(value.strip('"'), datatype.value)

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        node = diagram.factory.create(
            self.type(), **{"id": self.id, "brush": self.brush(), "height": self.height(), "width": self.width()}
        )
        node.setPos(self.pos())
        node.setText(self.text())
        node.setTextPos(node.mapFromScene(self.mapToScene(self.textPos())))
        return node

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        polygon = self.polygon.geometry()
        return polygon[self.IndexTR].y() - polygon[self.IndexBR].y()

    def identity(self):
        """
        Returns the identity of the current node.
        :rtype: Identity
        """
        match = RE_VALUE.match(self.text())
        if match:
            return Identity.Value
        return Identity.Individual

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawPolygon(self.selection.geometry())
        # SYNTAX VALIDATION
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawPolygon(self.background.geometry())
        # ITEM SHAPE
        painter.setPen(self.polygon.pen())
        painter.setBrush(self.polygon.brush())
        painter.drawPolygon(self.polygon.geometry())
        # RESIZE HANDLES
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        for polygon in self.handles:
            painter.setPen(polygon.pen())
            painter.setBrush(polygon.brush())
            painter.drawEllipse(polygon.geometry())

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        return path

    def resize(self, mousePos):
        """
        Handle the interactive resize of the shape.
        :type mousePos: QtCore.QPointF
        """
        snap = self.session.action("toggle_grid").isChecked()
        size = self.diagram.GridSize
        moved = self.label.isMoved()

        background = self.background.geometry()
        selection = self.selection.geometry()
        polygon = self.polygon.geometry()

        R = QtCore.QRectF(self.boundingRect())
        D = QtCore.QPointF(0, 0)

        mbrh = 68
        mbrw = 68

        self.prepareGeometryChange()

        if self.mp_Handle == self.HandleTL:

            fromX = self.mp_Bound.left()
            fromY = self.mp_Bound.top()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, -4, snap)
            toY = snapF(toY, size, -4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            newSideY = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newSideX = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSideY / 2
            newLeftRightTopY = (R.y() + R.height() / 2) - newSideY / 2
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSideX / 2
            newTopBottomRightX = (R.x() + R.width() / 2) + newSideX / 2

            selection[self.IndexLT] = QtCore.QPointF(R.left(), newLeftRightTopY)
            selection[self.IndexLB] = QtCore.QPointF(R.left(), newLeftRightBottomY)
            selection[self.IndexRT] = QtCore.QPointF(R.right(), newLeftRightTopY)
            selection[self.IndexRB] = QtCore.QPointF(R.right(), newLeftRightBottomY)
            selection[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top())
            selection[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top())
            selection[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom())
            selection[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom())
            selection[self.IndexEE] = QtCore.QPointF(R.left(), newLeftRightTopY)

            background[self.IndexLT] = QtCore.QPointF(R.left(), newLeftRightTopY)
            background[self.IndexLB] = QtCore.QPointF(R.left(), newLeftRightBottomY)
            background[self.IndexRT] = QtCore.QPointF(R.right(), newLeftRightTopY)
            background[self.IndexRB] = QtCore.QPointF(R.right(), newLeftRightBottomY)
            background[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top())
            background[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top())
            background[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom())
            background[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom())
            background[self.IndexEE] = QtCore.QPointF(R.left(), newLeftRightTopY)

            polygon[self.IndexLT] = QtCore.QPointF(R.left() + 4, newLeftRightTopY)
            polygon[self.IndexLB] = QtCore.QPointF(R.left() + 4, newLeftRightBottomY)
            polygon[self.IndexRT] = QtCore.QPointF(R.right() - 4, newLeftRightTopY)
            polygon[self.IndexRB] = QtCore.QPointF(R.right() - 4, newLeftRightBottomY)
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top() + 4)
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top() + 4)
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom() - 4)
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom() - 4)
            polygon[self.IndexEE] = QtCore.QPointF(R.left() + 4, newLeftRightTopY)

        elif self.mp_Handle == self.HandleTM:

            fromY = self.mp_Bound.top()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toY = snapF(toY, size, -4, snap)
            D.setY(toY - fromY)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            newSide = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSide / 2
            newLeftRightTopY = (R.y() + R.height() / 2) - newSide / 2

            selection[self.IndexTL] = QtCore.QPointF(background[self.IndexTL].x(), R.top())
            selection[self.IndexTR] = QtCore.QPointF(background[self.IndexTR].x(), R.top())
            selection[self.IndexLB] = QtCore.QPointF(background[self.IndexLB].x(), newLeftRightBottomY)
            selection[self.IndexRB] = QtCore.QPointF(background[self.IndexRB].x(), newLeftRightBottomY)
            selection[self.IndexLT] = QtCore.QPointF(background[self.IndexLT].x(), newLeftRightTopY)
            selection[self.IndexRT] = QtCore.QPointF(background[self.IndexRT].x(), newLeftRightTopY)
            selection[self.IndexEE] = QtCore.QPointF(background[self.IndexEE].x(), newLeftRightTopY)

            background[self.IndexTL] = QtCore.QPointF(background[self.IndexTL].x(), R.top())
            background[self.IndexTR] = QtCore.QPointF(background[self.IndexTR].x(), R.top())
            background[self.IndexLB] = QtCore.QPointF(background[self.IndexLB].x(), newLeftRightBottomY)
            background[self.IndexRB] = QtCore.QPointF(background[self.IndexRB].x(), newLeftRightBottomY)
            background[self.IndexLT] = QtCore.QPointF(background[self.IndexLT].x(), newLeftRightTopY)
            background[self.IndexRT] = QtCore.QPointF(background[self.IndexRT].x(), newLeftRightTopY)
            background[self.IndexEE] = QtCore.QPointF(background[self.IndexEE].x(), newLeftRightTopY)

            polygon[self.IndexTL] = QtCore.QPointF(polygon[self.IndexTL].x(), R.top() + 4)
            polygon[self.IndexTR] = QtCore.QPointF(polygon[self.IndexTR].x(), R.top() + 4)
            polygon[self.IndexLB] = QtCore.QPointF(polygon[self.IndexLB].x(), newLeftRightBottomY)
            polygon[self.IndexRB] = QtCore.QPointF(polygon[self.IndexRB].x(), newLeftRightBottomY)
            polygon[self.IndexLT] = QtCore.QPointF(polygon[self.IndexLT].x(), newLeftRightTopY)
            polygon[self.IndexRT] = QtCore.QPointF(polygon[self.IndexRT].x(), newLeftRightTopY)
            polygon[self.IndexEE] = QtCore.QPointF(polygon[self.IndexEE].x(), newLeftRightTopY)

        elif self.mp_Handle == self.HandleTR:

            fromX = self.mp_Bound.right()
            fromY = self.mp_Bound.top()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, +4, snap)
            toY = snapF(toY, size, -4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            newSideY = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newSideX = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSideY / 2
            newLeftRightTopY = (R.y() + R.height() / 2) - newSideY / 2
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSideX / 2
            newTopBottomRightX = (R.x() + R.width() / 2) + newSideX / 2

            selection[self.IndexLT] = QtCore.QPointF(R.left(), newLeftRightTopY)
            selection[self.IndexLB] = QtCore.QPointF(R.left(), newLeftRightBottomY)
            selection[self.IndexRT] = QtCore.QPointF(R.right(), newLeftRightTopY)
            selection[self.IndexRB] = QtCore.QPointF(R.right(), newLeftRightBottomY)
            selection[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top())
            selection[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top())
            selection[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom())
            selection[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom())
            selection[self.IndexEE] = QtCore.QPointF(R.left(), newLeftRightTopY)

            background[self.IndexLT] = QtCore.QPointF(R.left(), newLeftRightTopY)
            background[self.IndexLB] = QtCore.QPointF(R.left(), newLeftRightBottomY)
            background[self.IndexRT] = QtCore.QPointF(R.right(), newLeftRightTopY)
            background[self.IndexRB] = QtCore.QPointF(R.right(), newLeftRightBottomY)
            background[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top())
            background[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top())
            background[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom())
            background[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom())
            background[self.IndexEE] = QtCore.QPointF(R.left(), newLeftRightTopY)

            polygon[self.IndexLT] = QtCore.QPointF(R.left() + 4, newLeftRightTopY)
            polygon[self.IndexLB] = QtCore.QPointF(R.left() + 4, newLeftRightBottomY)
            polygon[self.IndexRT] = QtCore.QPointF(R.right() - 4, newLeftRightTopY)
            polygon[self.IndexRB] = QtCore.QPointF(R.right() - 4, newLeftRightBottomY)
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top() + 4)
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top() + 4)
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom() - 4)
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom() - 4)
            polygon[self.IndexEE] = QtCore.QPointF(R.left() + 4, newLeftRightTopY)

        elif self.mp_Handle == self.HandleML:

            fromX = self.mp_Bound.left()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toX = snapF(toX, size, -4, snap)
            D.setX(toX - fromX)
            R.setLeft(toX)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())

            newSide = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSide / 2
            newTopBottomRightX = (R.x() + R.width() / 2) + newSide / 2

            selection[self.IndexLT] = QtCore.QPointF(R.left(), selection[self.IndexLT].y())
            selection[self.IndexLB] = QtCore.QPointF(R.left(), selection[self.IndexLB].y())
            selection[self.IndexEE] = QtCore.QPointF(R.left(), selection[self.IndexEE].y())
            selection[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, selection[self.IndexTL].y())
            selection[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, selection[self.IndexTR].y())
            selection[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, selection[self.IndexBL].y())
            selection[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, selection[self.IndexBR].y())

            background[self.IndexLT] = QtCore.QPointF(R.left(), background[self.IndexLT].y())
            background[self.IndexLB] = QtCore.QPointF(R.left(), background[self.IndexLB].y())
            background[self.IndexEE] = QtCore.QPointF(R.left(), background[self.IndexEE].y())
            background[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, background[self.IndexTL].y())
            background[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, background[self.IndexTR].y())
            background[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, background[self.IndexBL].y())
            background[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, background[self.IndexBR].y())

            polygon[self.IndexLT] = QtCore.QPointF(R.left() + 4, polygon[self.IndexLT].y())
            polygon[self.IndexLB] = QtCore.QPointF(R.left() + 4, polygon[self.IndexLB].y())
            polygon[self.IndexEE] = QtCore.QPointF(R.left() + 4, polygon[self.IndexEE].y())
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, polygon[self.IndexTL].y())
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, polygon[self.IndexTR].y())
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, polygon[self.IndexBL].y())
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, polygon[self.IndexBR].y())

        elif self.mp_Handle == self.HandleMR:

            fromX = self.mp_Bound.right()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toX = snapF(toX, size, +4, snap)
            D.setX(toX - fromX)
            R.setRight(toX)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())

            newSide = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newTopBottomRightX = (R.x() + R.width() / 2) + newSide / 2
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSide / 2

            selection[self.IndexRT] = QtCore.QPointF(R.right(), selection[self.IndexRT].y())
            selection[self.IndexRB] = QtCore.QPointF(R.right(), selection[self.IndexRB].y())
            selection[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, selection[self.IndexTL].y())
            selection[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, selection[self.IndexTR].y())
            selection[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, selection[self.IndexBL].y())
            selection[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, selection[self.IndexBR].y())

            background[self.IndexRT] = QtCore.QPointF(R.right(), background[self.IndexRT].y())
            background[self.IndexRB] = QtCore.QPointF(R.right(), background[self.IndexRB].y())
            background[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, background[self.IndexTL].y())
            background[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, background[self.IndexTR].y())
            background[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, background[self.IndexBL].y())
            background[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, background[self.IndexBR].y())

            polygon[self.IndexRT] = QtCore.QPointF(R.right() - 4, polygon[self.IndexRT].y())
            polygon[self.IndexRB] = QtCore.QPointF(R.right() - 4, polygon[self.IndexRB].y())
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, polygon[self.IndexTL].y())
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, polygon[self.IndexTR].y())
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, polygon[self.IndexBL].y())
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, polygon[self.IndexBR].y())

        elif self.mp_Handle == self.HandleBL:

            fromX = self.mp_Bound.left()
            fromY = self.mp_Bound.bottom()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, -4, snap)
            toY = snapF(toY, size, +4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            newSideY = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newSideX = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSideY / 2
            newLeftRightTopY = (R.y() + R.height() / 2) - newSideY / 2
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSideX / 2
            newTopBottomRightX = (R.x() + R.width() / 2) + newSideX / 2

            selection[self.IndexLT] = QtCore.QPointF(R.left(), newLeftRightTopY)
            selection[self.IndexLB] = QtCore.QPointF(R.left(), newLeftRightBottomY)
            selection[self.IndexRT] = QtCore.QPointF(R.right(), newLeftRightTopY)
            selection[self.IndexRB] = QtCore.QPointF(R.right(), newLeftRightBottomY)
            selection[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top())
            selection[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top())
            selection[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom())
            selection[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom())
            selection[self.IndexEE] = QtCore.QPointF(R.left(), newLeftRightTopY)

            background[self.IndexLT] = QtCore.QPointF(R.left(), newLeftRightTopY)
            background[self.IndexLB] = QtCore.QPointF(R.left(), newLeftRightBottomY)
            background[self.IndexRT] = QtCore.QPointF(R.right(), newLeftRightTopY)
            background[self.IndexRB] = QtCore.QPointF(R.right(), newLeftRightBottomY)
            background[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top())
            background[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top())
            background[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom())
            background[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom())
            background[self.IndexEE] = QtCore.QPointF(R.left(), newLeftRightTopY)

            polygon[self.IndexLT] = QtCore.QPointF(R.left() + 4, newLeftRightTopY)
            polygon[self.IndexLB] = QtCore.QPointF(R.left() + 4, newLeftRightBottomY)
            polygon[self.IndexRT] = QtCore.QPointF(R.right() - 4, newLeftRightTopY)
            polygon[self.IndexRB] = QtCore.QPointF(R.right() - 4, newLeftRightBottomY)
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top() + 4)
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top() + 4)
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom() - 4)
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom() - 4)
            polygon[self.IndexEE] = QtCore.QPointF(R.left() + 4, newLeftRightTopY)

        elif self.mp_Handle == self.HandleBM:

            fromY = self.mp_Bound.bottom()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toY = snapF(toY, size, +4, snap)
            D.setY(toY - fromY)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            newSide = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightTopY = (R.y() + R.height() / 2) - newSide / 2
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSide / 2

            selection[self.IndexBL] = QtCore.QPointF(selection[self.IndexBL].x(), R.bottom())
            selection[self.IndexBR] = QtCore.QPointF(selection[self.IndexBR].x(), R.bottom())
            selection[self.IndexLB] = QtCore.QPointF(selection[self.IndexLB].x(), newLeftRightBottomY)
            selection[self.IndexRB] = QtCore.QPointF(selection[self.IndexRB].x(), newLeftRightBottomY)
            selection[self.IndexLT] = QtCore.QPointF(selection[self.IndexLT].x(), newLeftRightTopY)
            selection[self.IndexRT] = QtCore.QPointF(selection[self.IndexRT].x(), newLeftRightTopY)
            selection[self.IndexEE] = QtCore.QPointF(selection[self.IndexEE].x(), newLeftRightTopY)

            background[self.IndexBL] = QtCore.QPointF(background[self.IndexBL].x(), R.bottom())
            background[self.IndexBR] = QtCore.QPointF(background[self.IndexBR].x(), R.bottom())
            background[self.IndexLB] = QtCore.QPointF(background[self.IndexLB].x(), newLeftRightBottomY)
            background[self.IndexRB] = QtCore.QPointF(background[self.IndexRB].x(), newLeftRightBottomY)
            background[self.IndexLT] = QtCore.QPointF(background[self.IndexLT].x(), newLeftRightTopY)
            background[self.IndexRT] = QtCore.QPointF(background[self.IndexRT].x(), newLeftRightTopY)
            background[self.IndexEE] = QtCore.QPointF(background[self.IndexEE].x(), newLeftRightTopY)

            polygon[self.IndexBL] = QtCore.QPointF(polygon[self.IndexBL].x(), R.bottom() - 4)
            polygon[self.IndexBR] = QtCore.QPointF(polygon[self.IndexBR].x(), R.bottom() - 4)
            polygon[self.IndexLB] = QtCore.QPointF(polygon[self.IndexLB].x(), newLeftRightBottomY)
            polygon[self.IndexRB] = QtCore.QPointF(polygon[self.IndexRB].x(), newLeftRightBottomY)
            polygon[self.IndexLT] = QtCore.QPointF(polygon[self.IndexLT].x(), newLeftRightTopY)
            polygon[self.IndexRT] = QtCore.QPointF(polygon[self.IndexRT].x(), newLeftRightTopY)
            polygon[self.IndexEE] = QtCore.QPointF(polygon[self.IndexEE].x(), newLeftRightTopY)

        elif self.mp_Handle == self.HandleBR:

            fromX = self.mp_Bound.right()
            fromY = self.mp_Bound.bottom()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, +4, snap)
            toY = snapF(toY, size, +4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            newSideY = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newSideX = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSideY / 2
            newLeftRightTopY = (R.y() + R.height() / 2) - newSideY / 2
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSideX / 2
            newTopBottomRightX = (R.x() + R.width() / 2) + newSideX / 2

            selection[self.IndexLT] = QtCore.QPointF(R.left(), newLeftRightTopY)
            selection[self.IndexLB] = QtCore.QPointF(R.left(), newLeftRightBottomY)
            selection[self.IndexRT] = QtCore.QPointF(R.right(), newLeftRightTopY)
            selection[self.IndexRB] = QtCore.QPointF(R.right(), newLeftRightBottomY)
            selection[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top())
            selection[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top())
            selection[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom())
            selection[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom())
            selection[self.IndexEE] = QtCore.QPointF(R.left(), newLeftRightTopY)

            background[self.IndexLT] = QtCore.QPointF(R.left(), newLeftRightTopY)
            background[self.IndexLB] = QtCore.QPointF(R.left(), newLeftRightBottomY)
            background[self.IndexRT] = QtCore.QPointF(R.right(), newLeftRightTopY)
            background[self.IndexRB] = QtCore.QPointF(R.right(), newLeftRightBottomY)
            background[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top())
            background[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top())
            background[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom())
            background[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom())
            background[self.IndexEE] = QtCore.QPointF(R.left(), newLeftRightTopY)

            polygon[self.IndexLT] = QtCore.QPointF(R.left() + 4, newLeftRightTopY)
            polygon[self.IndexLB] = QtCore.QPointF(R.left() + 4, newLeftRightBottomY)
            polygon[self.IndexRT] = QtCore.QPointF(R.right() - 4, newLeftRightTopY)
            polygon[self.IndexRB] = QtCore.QPointF(R.right() - 4, newLeftRightBottomY)
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top() + 4)
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top() + 4)
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom() - 4)
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom() - 4)
            polygon[self.IndexEE] = QtCore.QPointF(R.left() + 4, newLeftRightTopY)

        self.background.setGeometry(background)
        self.selection.setGeometry(selection)
        self.polygon.setGeometry(polygon)

        self.updateNode(selected=True, handle=self.mp_Handle, anchors=(self.mp_Data, D))
        self.updateTextPos(moved=moved)

    def setIdentity(self, identity):
        """
        Set the identity of the current node.
        :type identity: Identity
        """
        pass

    def setText(self, text):
        """
        Set the label text: will additionally block label editing if a literal is being.
        :type text: str
        """
        self.label.setEditable(RE_VALUE.match(text) is None)
        self.label.setText(text)
        self.label.setAlignment(QtCore.Qt.AlignCenter)

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        self.label.setPos(pos)

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        for polygon in self.handles:
            path.addEllipse(polygon.geometry())
        return path

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        return self.label.text()

    def textPos(self):
        """
        Returns the current label position in item coordinates.
        :rtype: QPointF
        """
        return self.label.pos()

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        self.label.updatePos(*args, **kwargs)

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        polygon = self.polygon.geometry()
        return polygon[self.IndexRT].x() - polygon[self.IndexLT].x()

    def __repr__(self):
        """
        Returns repr(self).
        """
        return "{0}:{1}:{2}".format(self.__class__.__name__, self.text(), self.id)