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)
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)
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)
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 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)
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 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()
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)
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()
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)
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)
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)
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)
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)