예제 #1
0
class NodeTemplateItem():
    ''' 
    This represents one node template on the diagram.  A node template can be on many diagrams
    This class creates the rectangle graphics item and the text graphics item and adds them to the scene.
    '''
    def __init__(self, scene, x, y, nodeTemplateDict=None, NZID=None):
        self.scene = scene
        self.logMsg = None
        self.x = x
        self.y = y
        self.nodeTemplateDict = nodeTemplateDict
        #        self.name = self.nodeTemplateDict.get("name", "")   THIS HAS BEEN REPLACED BY THE name FUNCTION - SEE BELOW
        self.diagramType = "Node Template"
        self.displayText = None
        self.model = self.scene.parent.model
        self.gap = 100
        self.relList = []
        # assign a unique key if it doesn't already have one
        if NZID == None:
            self.NZID = str(uuid.uuid4())
        else:
            self.NZID = NZID

        # init graphics objects to none
        self.TNode = None
        self.TNtext = None

        # draw the node template on the diagram
        self.drawIt()

    def name(self, ):
        return self.nodeTemplateDict.get("name", "")

    def getX(self, ):
        return self.TNode.boundingRect().x()

    def getY(self, ):
        return self.TNode.boundingRect().y()

    def getHeight(self, ):
        return self.TNode.boundingRect().height()

    def getWidth(self, ):
        return self.TNode.boundingRect().width()

    def getRelList(self, ):
        '''return a list of all relationitems that are inbound or outbound from this node template.
          do not include self referencing relationships
        '''
        return [
            diagramItem
            for key, diagramItem in self.scene.parent.itemDict.items()
            if diagramItem.diagramType == "Relationship Template" and (
                diagramItem.startNZID == self.NZID
                or diagramItem.endNZID == self.NZID)
        ]

    def getPoint(self, offset=None):
        '''
        This function is used by the template diagram to calculate the location to drop a node template on the diagram
        '''
        if offset is None:
            return QPointF(self.x, self.y)
        else:
            return QPointF(self.x + offset, self.y + offset)

    def getFormat(self, ):
        '''
        determine if the Node Template  has a template format or should use the project default format
        '''
        # get the node Template custom format
        customFormat = self.nodeTemplateDict.get("TNformat", None)

        if not customFormat is None:
            # get the template custom format
            self.nodeFormat = TNodeFormat(formatDict=customFormat)
        else:
            # get the project default format
            self.nodeFormat = TNodeFormat(
                formatDict=self.model.modelData["TNformat"])

    def clearItem(self, ):

        if (not self.TNode is None and not self.TNode.scene() is None):
            self.TNode.scene().removeItem(self.TNode)
        if (not self.TNtext is None and not self.TNtext.scene() is None):
            self.TNtext.scene().removeItem(self.TNtext)

    def drawIt(self, ):

        # get current format as it may have changed
        self.getFormat()

        # create the qgraphicsItems if they don't exist
        if self.TNode is None:
            # create the rectangle
            self.TNode = QGraphicsRectItem(QRectF(
                self.x, self.y, self.nodeFormat.formatDict["nodeWidth"],
                self.nodeFormat.formatDict["nodeHeight"]),
                                           parent=None)
            self.TNode.setZValue(NODELAYER)
            self.TNode.setFlag(QGraphicsItem.ItemIsMovable, True)
            self.TNode.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
            self.TNode.setFlag(QGraphicsItem.ItemIsSelectable, True)
            self.TNode.setSelected(True)
            self.TNode.setData(1, self.NZID)  # get with self.INode.data(1)
            self.TNode.setData(ITEMTYPE, NODETEMPLATE)
            # create the text box
            self.TNtext = QGraphicsTextItem("", parent=None)
            self.TNtext.setPos(self.x, self.y)
            self.TNtext.setFlag(QGraphicsItem.ItemIsMovable, True)
            self.TNtext.setFlag(QGraphicsItem.ItemIsSelectable, False)
            self.TNtext.setData(NODEID, self.NZID)
            self.TNtext.setData(ITEMTYPE, NODETEMPLATETEXT)
            self.TNtext.setZValue(NODELAYER)
            # save the location
            self.x = self.TNode.sceneBoundingRect().x()
            self.y = self.TNode.sceneBoundingRect().y()
            # generate the html and resize the rectangle
            self.formatItem()
            # add the graphics items to the scene
            self.scene.addItem(self.TNode)
            self.scene.addItem(self.TNtext)
        else:
            # generate the html and resize the rectangle
            self.formatItem()

    def formatItem(self, ):

        # configure the formatting aspects of the qgraphics item
        pen = self.nodeFormat.pen()
        brush = self.nodeFormat.brush()
        self.TNode.setBrush(brush)
        self.TNode.setPen(pen)

        # generate the HTML
        genHTML = self.generateHTML()
        self.TNtext.prepareGeometryChange()
        #        print("before html bounding rectangle width:{}".format(self.TNtext.boundingRect().width()))
        #        print("before html text width:{}".format(self.TNtext.textWidth()))
        self.TNtext.setTextWidth(
            -1
        )  # reset the width to unkonwn so it will calculate a new width based on the new html
        self.TNtext.setHtml(genHTML)
        #        print("after html bounding rectangle width:{}".format(self.TNtext.boundingRect().width()))
        #        print("after html text width:{}".format(self.TNtext.textWidth()))

        # make sure minimum width of 120
        if self.TNtext.boundingRect().width() < 120:
            self.TNtext.setTextWidth(120)
        else:
            self.TNtext.setTextWidth(
                self.TNtext.boundingRect().width()
            )  # you have to do a setTextWidth to get the html to render correctly.

        # set the rectangle item to the same size as the formatted html
        self.TNode.prepareGeometryChange()
        currentRect = self.TNode.rect()
        # insure minimum height of 120
        if self.TNtext.boundingRect().height() < 120:
            currentRect.setHeight(120)
        else:
            currentRect.setHeight(self.TNtext.boundingRect().height())
        currentRect.setWidth(self.TNtext.boundingRect().width())
        self.TNode.setRect(currentRect)

    def generateHTML(self, ):
        '''
        Generate the HTML that formats the node template data inside the rectangle
        '''
        # generate the html
        prefix = "<!DOCTYPE html><html><body>"
        #        head = "<head><style>table, th, td {border: 1px solid black; border-collapse: collapse;}</style></head>"
        suffix = "</body></html>"
        #        blankRow = "<tr><td><left>{}</left></td><td><left>{}</left></td><td><left>{}</left></td><td><left>{}</left></td></tr>".format("", "", "", "")

        name = "<center><b>{}</b></center>".format(
            self.nodeTemplateDict.get("name", ""))
        lbls = self.genLblHTML()
        props = self.genPropHTML()
        genHTML = "{}{}<hr>{}<br><hr>{}{}".format(prefix, name, lbls, props,
                                                  suffix)
        #        print("{} html: {}".format(self.name(), genHTML))

        return genHTML

    def genLblHTML(self):
        #        html = '<table width="90%">'
        html = '<table style="width:90%;border:1px solid black;">'
        if len(self.nodeTemplateDict.get("labels", [])) > 0:
            for lbl in self.nodeTemplateDict.get("labels", []):
                if lbl[NODEKEY] == Qt.Checked:
                    nk = "NK"
                else:
                    nk = "&nbsp;&nbsp;"
                if lbl[REQUIRED] == Qt.Checked:
                    rq = "R"
                else:
                    rq = ""

                html = html + '<tr align="left"><td width="15%"><left>{}</left></td><td width="65%"><left>{}</left></td><td width="10%"><left>{}</left></td><td width="10%"><left>{}</left></td></tr>'.format(
                    nk, lbl[LABEL], "", rq)
            html = html + "</table>"
        else:
            html = '<tr align="left"><td width="15%"><left>{}</left></td><td  width="65%"><left>{}</left></td><td width="10%"><left>{}</left></td><td width="10%"><left>{}</left></td></tr>'.format(
                "  ", "NO{}LABELS".format("&nbsp;"), "", "")
            html = html + "</table>"

        return html

    def genPropHTML(self):
        #        PROPERTY, DATATYPE, PROPREQ, DEFAULT, EXISTS, UNIQUE, PROPNODEKEY
        html = '<table style="width:90%;border:1px solid black;">'
        if len(self.nodeTemplateDict.get("properties", [])) > 0:
            for prop in self.nodeTemplateDict.get("properties", []):
                if prop[PROPNODEKEY] == Qt.Checked:
                    nk = "NK"
                else:
                    nk = "&nbsp;&nbsp;"
                if prop[PROPREQ] == Qt.Checked:
                    rq = "R"
                else:
                    rq = ""
                if prop[EXISTS] == Qt.Checked:
                    ex = "E"
                else:
                    ex = ""
                if prop[UNIQUE] == Qt.Checked:
                    uq = "U"
                else:
                    uq = ""
                html = html + '<tr align="left"><td width="15%"><left>{}</left></td><td width="65%"><left>{}</left></td><td width="10%"><left>{}</left></td><td width="10%"><left>{}</left></td><td width="10%"><left>{}</left></td></tr>'.format(
                    nk, prop[PROPERTY], rq, ex, uq)
            html = html + "</table>"
        else:
            html = html + '<tr align="left"><td width="15%"><left>{}</left></td><td width="65%"><left>{}</left></td><td width="10%"><left>{}</left></td><td width="10%"><left>{}</left></td></tr>'.format(
                "&nbsp;&nbsp;", "NO{}PROPERTIES".format("&nbsp;"), "", "", "")
            html = html + "</table>"
        return html

    def moveIt(self, dx, dy):
        '''
        Move the node rectangle and the node textbox to the delta x,y coordinate.
        '''
        #        print("before moveIt: sceneboundingrect {} ".format( self.INode.sceneBoundingRect()))

        self.TNode.moveBy(dx, dy)
        self.x = self.TNode.sceneBoundingRect().x()
        self.y = self.TNode.sceneBoundingRect().y()
        self.TNtext.moveBy(dx, dy)
        #        print("after moveIt: sceneboundingrect {} ".format( self.INode.sceneBoundingRect()))
        # now redraw all the relationships
        self.drawRels()

    def drawRels(self, ):
        '''Redraw all the relationship lines connected to the Node Template Rectangle'''
        # get a list of the relationship items connected to this node template
        self.relList = self.getRelList()

        # assign the correct inbound/outbound side for the rel
        for rel in self.relList:
            if rel.endNodeItem.NZID != rel.startNodeItem.NZID:  # ignore bunny ears
                rel.assignSide()
        # get a set of all the nodes and sides involved
        nodeSet = set()
        for rel in self.relList:
            if rel.endNodeItem.NZID != rel.startNodeItem.NZID:  # ignore bunny ears
                nodeSet.add((rel.endNodeItem, rel.inboundSide))
                nodeSet.add((rel.startNodeItem, rel.outboundSide))

        # tell each node side to assign rel locations
        for nodeSide in nodeSet:
            nodeSide[0].assignPoint(nodeSide[1])

        ############################################

        # now tell them all to redraw
        for rel in self.relList:
            rel.drawIt2()

    def calcOffset(self, index, totRels):
        offset = [-60, -40, -20, 0, 20, 40, 60]
        offsetStart = [3, 2, 2, 1, 1, 0, 0]
        if totRels > 7:
            totRels = 7
        return offset[offsetStart[totRels - 1] + index]

    def assignPoint(self, side):
        # go through all the rels on a side and assign their x,y coord for that side
        self.relList = self.getRelList()
        sideList = [
            rel for rel in self.relList
            if ((rel.startNZID == self.NZID and rel.outboundSide == side) or (
                rel.endNZID == self.NZID and rel.inboundSide == side))
        ]
        totRels = len(sideList)
        if totRels > 0:
            if side == R:
                # calc center of the side
                x = self.x + self.getWidth()
                y = self.y + self.getHeight() / 2
                # sort the rels connected to this side by the y value
                sideList.sort(key=self.getSortY)
                # assign each of them a position on the side starting in the center and working out in both directions
                for index, rel in enumerate(sideList):
                    if rel.startNZID == self.NZID:
                        rel.outboundPoint = QPointF(
                            x, y + (self.calcOffset(index, totRels)))
                    if rel.endNZID == self.NZID:
                        rel.inboundPoint = QPointF(
                            x, y + (self.calcOffset(index, totRels)))
            elif side == L:
                x = self.x
                y = self.y + self.getHeight() / 2
                sideList.sort(key=self.getSortY)
                for index, rel in enumerate(sideList):
                    if rel.startNZID == self.NZID:
                        rel.outboundPoint = QPointF(
                            x, y + (self.calcOffset(index, totRels)))
                    if rel.endNZID == self.NZID:
                        rel.inboundPoint = QPointF(
                            x, y + (self.calcOffset(index, totRels)))
            elif side == TOP:
                x = self.x + self.getWidth() / 2
                y = self.y
                sideList.sort(key=self.getSortX)
                for index, rel in enumerate(sideList):
                    if rel.startNZID == self.NZID:
                        rel.outboundPoint = QPointF(
                            x + (self.calcOffset(index, totRels)), y)
                    if rel.endNZID == self.NZID:
                        rel.inboundPoint = QPointF(
                            x + (self.calcOffset(index, totRels)), y)
            elif side == BOTTOM:
                x = self.x + self.getWidth() / 2
                y = self.y + self.getHeight()
                sideList.sort(key=self.getSortX)
                for index, rel in enumerate(sideList):
                    if rel.startNZID == self.NZID:
                        rel.outboundPoint = QPointF(
                            x + (self.calcOffset(index, totRels)), y)
                    if rel.endNZID == self.NZID:
                        rel.inboundPoint = QPointF(
                            x + (self.calcOffset(index, totRels)), y)
            else:
                print("error, no side")

    def getSortY(self, rel):
        # if this node is the start node then return the end node's Y
        if rel.startNZID == self.NZID:
            return rel.endNodeItem.TNode.sceneBoundingRect().center().y()
        # if this node is the end node then return the start node's Y
        if rel.endNZID == self.NZID:
            return rel.startNodeItem.TNode.sceneBoundingRect().center().y()
        # this should never happen
        return 0

    def getSortX(self, rel):
        # if this node is the start node then return the end node's X
        if rel.startNZID == self.NZID:
            return rel.endNodeItem.TNode.sceneBoundingRect().center().x()
        # if this node is the end node then return the start node's X
        if rel.endNZID == self.NZID:
            return rel.startNodeItem.TNode.sceneBoundingRect().center().x()
        # this should never happen
        return 0

    def getObjectDict(self, ):
        '''
        This function returns a dictionary with all the data that represents this node template item.  
        The dictionary is added to the Instance Diagram dictionary.'''
        objectDict = {}
        objectDict["NZID"] = self.NZID
        objectDict["name"] = self.nodeTemplateDict.get("name", "")
        objectDict["displayText"] = self.displayText
        objectDict["x"] = self.TNode.sceneBoundingRect().x()
        objectDict["y"] = self.TNode.sceneBoundingRect().y()
        objectDict["diagramType"] = self.diagramType
        objectDict["labels"] = self.nodeTemplateDict.get("labels", [])
        objectDict["properties"] = self.nodeTemplateDict.get("properties", [])

        return objectDict

    def setLogMethod(self, logMethod=None):
        if logMethod is None:
            if self.logMsg is None:
                self.logMsg = self.noLog
        else:
            self.logMsg = logMethod

    def noLog(self, msg):
        return
예제 #2
0
class QmyMainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)  #调用父类构造函数,创建窗体
        self.ui = Ui_MainWindow()  #创建UI对象
        self.ui.setupUi(self)  #构造UI界面

        self.player = QMediaPlayer(self)  #创建视频播放器
        self.player.setNotifyInterval(1000)  #信息更新周期, ms

        scene = QGraphicsScene(self)
        self.ui.graphicsView.setScene(scene)

        self.videoItem = QGraphicsVideoItem()  #视频显示画面
        self.videoItem.setSize(QSizeF(320, 220))
        self.videoItem.setFlag(QGraphicsItem.ItemIsMovable)
        self.videoItem.setFlag(QGraphicsItem.ItemIsSelectable)
        self.videoItem.setFlag(QGraphicsItem.ItemIsFocusable)

        scene.addItem(self.videoItem)
        self.player.setVideoOutput(self.videoItem)  #设置视频显示图形项

        self.textItem = QGraphicsTextItem("面朝大海,春暖花开")  #弹幕文字
        font = self.textItem.font()
        font.setPointSize(20)
        self.textItem.setFont(font)
        self.textItem.setDefaultTextColor(Qt.red)
        self.textItem.setPos(100, 220)
        self.textItem.setFlag(QGraphicsItem.ItemIsMovable)
        self.textItem.setFlag(QGraphicsItem.ItemIsSelectable)
        self.textItem.setFlag(QGraphicsItem.ItemIsFocusable)
        scene.addItem(self.textItem)

        self.ui.btnText.setCheckable(True)  #弹幕文字按钮
        self.ui.btnText.setChecked(True)

        self.__duration = ""
        self.__curPos = ""
        self.player.stateChanged.connect(self.do_stateChanged)
        self.player.positionChanged.connect(self.do_positionChanged)
        self.player.durationChanged.connect(self.do_durationChanged)

##  ==============自定义功能函数========================

##  ==============event处理函数==========================

    def closeEvent(self, event):  #窗体关闭时
        # 窗口关闭时不能自动停止播放,需手动停止
        if (self.player.state() == QMediaPlayer.PlayingState):
            self.player.stop()

##  ==========由connectSlotsByName()自动连接的槽函数============

    @pyqtSlot()  ##打开文件
    def on_btnOpen_clicked(self):
        curPath = QDir.currentPath()  #获取系统当前目录
        ##      curPath=os.getcwd()
        title = "选择视频文件"
        filt = "视频文件(*.wmv *.avi);;所有文件(*.*)"
        fileName, flt = QFileDialog.getOpenFileName(self, title, curPath, filt)

        if (fileName == ""):
            return

        fileInfo = QFileInfo(fileName)
        baseName = fileInfo.fileName()
        ##      baseName=os.path.basename(fileName)
        self.ui.LabCurMedia.setText(baseName)
        curPath = fileInfo.absolutePath()
        QDir.setCurrent(curPath)  #重设当前目录

        media = QMediaContent(QUrl.fromLocalFile(fileName))

        self.player.setMedia(media)  #设置播放文件
        self.player.play()

    @pyqtSlot()  ##播放
    def on_btnPlay_clicked(self):
        self.player.play()

    @pyqtSlot()  ##暂停
    def on_btnPause_clicked(self):
        self.player.pause()

    @pyqtSlot()  ##停止
    def on_btnStop_clicked(self):
        self.player.stop()

    @pyqtSlot()  ##全屏
    def on_btnFullScreen_clicked(self):
        self.videoWidget.setFullScreen(True)

    @pyqtSlot()  ##静音按钮
    def on_btnSound_clicked(self):
        mute = self.player.isMuted()
        self.player.setMuted(not mute)
        if mute:
            self.ui.btnSound.setIcon(QIcon(":/icons/images/volumn.bmp"))
        else:
            self.ui.btnSound.setIcon(QIcon(":/icons/images/mute.bmp"))

    @pyqtSlot(int)  ##音量调节
    def on_sliderVolumn_valueChanged(self, value):
        self.player.setVolume(value)

    @pyqtSlot(int)  ##播放进度调节
    def on_sliderPosition_valueChanged(self, value):
        self.player.setPosition(value)

    @pyqtSlot()  ##放大
    def on_btnZoomIn_clicked(self):
        sc = self.videoItem.scale()
        self.videoItem.setScale(sc + 0.1)

    @pyqtSlot()  ##缩小
    def on_btnZoomOut_clicked(self):
        sc = self.videoItem.scale()
        self.videoItem.setScale(sc - 0.1)

    @pyqtSlot(bool)  ##弹幕
    def on_btnText_clicked(self, checked):
        self.textItem.setVisible(checked)

##  =============自定义槽函数===============================

    def do_stateChanged(self, state):
        isPlaying = (state == QMediaPlayer.PlayingState)

        self.ui.btnPlay.setEnabled(not isPlaying)
        self.ui.btnPause.setEnabled(isPlaying)
        self.ui.btnStop.setEnabled(isPlaying)

    def do_durationChanged(self, duration):
        self.ui.sliderPosition.setMaximum(duration)

        secs = duration / 1000  #秒
        mins = secs / 60  #分钟
        secs = secs % 60  #余数秒
        self.__duration = "%d:%d" % (mins, secs)
        self.ui.LabRatio.setText(self.__curPos + "/" + self.__duration)

    def do_positionChanged(self, position):
        if (self.ui.sliderPosition.isSliderDown()):
            return  #如果正在拖动滑条,退出

        self.ui.sliderPosition.setSliderPosition(position)

        secs = position / 1000  #秒
        mins = secs / 60  #分钟
        secs = secs % 60  #余数秒
        self.__curPos = "%d:%d" % (mins, secs)
        self.ui.LabRatio.setText(self.__curPos + "/" + self.__duration)
예제 #3
0
class CallOut():
    ''' This represents a callouton the diagram
        This class creates a text item and then surrounds it with a polygon that is a rectangle
        with a pointer to another object on the diagram.
        This can be used by hover over functions or be displayed as a part of a node or relationship
        '''
    def __init__(self, scene, text, anchorPoint, diagramType, format):

        self.scene = scene
        self.model = self.scene.parent.model
        self.text = text
        self.anchorPoint = anchorPoint
        self.diagramType = diagramType
        self.format = format

        # initialize the two qgraphicsitems needed to draw a relationship to None
        self.itemText = None
        self.itemPolygon = None
        self.drawIt

    def name(self, ):
        return "no name"

    def NZID(self, ):
        return None

    def clearItem(self, ):

        if (not self.itemText is None and not self.itemText.scene() is None):
            self.itemText.scene().removeItem(self.itemText)
        if (not self.itemPolygon is None
                and not self.itemPolygon.scene() is None):
            self.itemPolygon.scene().removeItem(self.itemPolygon)

    def drawIt(self, ):
        '''
        draw the callout
        '''

        # if the polygon and text graphics items already exist on the scene then delete them
        self.clearItem()

        # draw the relationship arc
        pen = self.format.pen()
        brush = self.format.brush()

        # create text box
        # draw the text
        self.itemText = QGraphicsTextItem(self.relationInstance.relName,
                                          parent=None)
        self.itemText.setZValue(CALLOUTLAYER)
        self.itemText.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.itemText.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.itemText.setSelected(False)
        self.itemText.setData(NODEID, self.relationInstance.NZID)
        self.itemText.setData(ITEMTYPE, CALLOUT)
        self.itemText.setHtml(self.genTextHTML())
        # set the position of the text
        self.itemText.setPos(self.anchorPoint)

        # get the height and width of the text graphics item
        th = self.IRtext.boundingRect().height()
        tw = self.IRtext.boundingRect().width()

        #create an empty polygon
        arrowPolygon = QPolygonF()
        # add callout points
        arrowPolygon.append(self.anchorPoint)
        arrowPolygon.append(
            QPointF(self.anchorPoint.x() + tw, self.anchorPoint.y()))
        arrowPolygon.append(
            QPointF(self.anchorPoint.x() + tw, self.anchorPoint.y()))
        arrowPolygon.append(
            QPointF(self.anchorPoint.x() + tw,
                    self.anchorPoint.y() + th))
        arrowPolygon.append(
            QPointF(self.anchorPoint.x(),
                    self.anchorPoint.y() + th))
        self.itemPolygon = QGraphicsPolygonItem(
            arrowPolygon,
            parent=None,
        )
        self.itemPolygon.setZValue(CALLOUTLAYER)
        self.itemPolygon.setBrush(brush)
        self.itemPolygon.setPen(pen)
        self.itemPolygon.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.itemPolygon.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
        self.itemPolygon.setFlag(QGraphicsItem.ItemIsSelectable, False)
        self.itemPolygon.setSelected(False)

        # set data in the RelLine object
        self.IRel.setData(NODEID, self.relationInstance.NZID)
        self.IRel.setData(ITEMTYPE, RELINSTANCEARC)
        # add the polygon object to the scene
        self.scene.addItem(self.itemPolygon)
        # add text to the scene
        self.scene.addItem(self.itemText)

    def updateText(self, ):
        #        # force the node instance to update its values in case it has been updated from another diagram or the tree view
        #        self.relationInstance.reloadDictValues()
        #        self.IRtext.setPlainText(self.relationInstance.relName)
        self.itemText.setHtml(self.genTextHTML())

    def genTextHTML(self):
        '''generate html to display the text
        '''
        prefix = '<html><body>'
        suffix = "</body></html>"
        myHTML = ('{}<p><font size="1"> [{}]</font></p>{}'.format(
            prefix, self.text, suffix))
        return myHTML

    def moveIt(self, ):
        self.drawIt()
예제 #4
0
파일: main.py 프로젝트: vnea/PyQt5Test
from PyQt5.QtGui import QStandardItemModel,QStandardItem

if __name__ == "__main__":

    app = QApplication(sys.argv)
    
    mainWindow = QMainWindow()
    mainWindow.setWindowTitle("PyQt5Test")
    
    w = QWidget(mainWindow)
    
    elipse = QGraphicsEllipseItem(200, 200, 200, 200)
    elipse2 = QGraphicsEllipseItem(100, 100, 100, 100)
    text = QGraphicsTextItem("TEST", elipse)
    text.setTextInteractionFlags(Qt.TextEditorInteraction)
    text.setFlag(QGraphicsItem.ItemIsMovable)
    elipse.setFlag(QGraphicsItem.ItemIsMovable)
    elipse2.setFlag(QGraphicsItem.ItemIsMovable)
    
    scene = QGraphicsScene()
    scene.addItem(text)
    scene.addItem(elipse)
    scene.addItem(elipse2)

    view = QGraphicsView(scene, w)
    textEdit = QTextEdit("Moon text", w)
    

    
    #w.showMaximized()
    treeView = QTreeView()
예제 #5
0
class NodeItem():
    ''' 
    This represents one node on the diagram.
    This class creates the ellipse graphics item and the text graphics item and adds them to the scene.
    '''
    def __init__(self, scene, x, y, nodeInstance=None):
        self.scene = scene
        self.logMsg = None

        self.x = x
        self.y = y
        self.itemInstance = nodeInstance
        self.diagramType = self.itemInstance.diagramType
        self.displayText = None
        self.model = self.scene.parent.model
        self.neoCon = self.scene.parent.model.modelNeoCon
        self.getFormat()
        # remember current width and height
        self.oldNodeWidth = 0
        self.oldNodeHeight = 0
        # init graphics objects to none
        self.INode = None
        self.INtext = None
        #        # init list of qgrapphicellipseitems to none
        #        self.ellipsePoints = []
        #        self.ellipseGraphicItems = []
        # draw the ellipse
        self.drawIt()

    def name(self, ):
        return self.itemInstance.NZID

    def NZID(self, ):
        return self.itemInstance.NZID

    def getFormat(self, ):
        '''
        determine the format to use to draw the instance node
        - start with the project default
        - if the instance node has a template then use the instance format defined on the template
        '''
        # get the default
        self.nodeFormat = INodeFormat(
            formatDict=self.model.modelData["INformat"])
        # get a custom template format if there is one
        if not self.itemInstance.nodeTemplate is None:
            index, nodeTemplateDict = self.model.getDictByName(
                topLevel="Node Template",
                objectName=self.itemInstance.nodeTemplate)
            if not nodeTemplateDict is None:
                self.instanceNodeFormatDict = nodeTemplateDict.get(
                    "INformat", None)
                if not self.instanceNodeFormatDict is None:
                    self.nodeFormat = INodeFormat(
                        formatDict=self.instanceNodeFormatDict)

    def clearItem(self, ):

        if (not self.INode is None and not self.INode.scene() is None):
            self.INode.scene().removeItem(self.INode)
        if (not self.INtext is None and not self.INtext.scene() is None):
            self.INtext.scene().removeItem(self.INtext)

#        # remove the points on the ellipse - this code is only for debugging
#        for point in self.ellipseGraphicItems:
#            if (not point is None and not point.scene() is None):
#                point.scene().removeItem(point)

    def drawIt(self, ):
        # force the node instance to update its values in case it has been updated from another diagram or the tree view
        self.itemInstance.reloadDictValues()
        # get current format as it may have changed
        self.getFormat()
        if self.oldNodeWidth != self.nodeFormat.formatDict[
                "nodeWidth"] or self.oldNodeHeight != self.nodeFormat.formatDict[
                    "nodeHeight"]:
            # remove graphic items that already exist
            self.clearItem()
            # create the node ellipse
            self.INode = QGraphicsEllipseItem(QRectF(
                self.x, self.y, self.nodeFormat.formatDict["nodeWidth"],
                self.nodeFormat.formatDict["nodeHeight"]),
                                              parent=None)
            # create the node text
            self.INtext = QGraphicsTextItem("", parent=None)
            self.INtext.setPos(self.x, self.y)
            self.x = self.INode.sceneBoundingRect().x()
            self.y = self.INode.sceneBoundingRect().y()
            #            print("after create items before drawIt: sceneboundingrect {} ".format( self.INode.sceneBoundingRect()))
            #            print("x:{} y:{}".format(self.x, self.y))
            self.formatItem()
            self.scene.addItem(self.INode)
            self.scene.addItem(self.INtext)
            #            # add points
            #            for point in self.ellipseGraphicItems:
            #                self.scene.addItem(point)

            # redraw all the rels associated to this node.
            self.moveRels()
        else:
            #            print("before drawIt: sceneboundingrect {} ".format( self.INode.sceneBoundingRect()))
            #            print("x:{} y:{}".format(self.x, self.y))
            self.formatItem()
        # remember current width and height
        self.oldNodeWidth = self.nodeFormat.formatDict["nodeWidth"]
        self.oldNodeHeight = self.nodeFormat.formatDict["nodeHeight"]
#        print("after drawIt: sceneboundingrect {} ".format( self.INode.sceneBoundingRect()))
#        print("x:{} y:{}".format(self.x, self.y))

#    def genPoints(self, ):
#        '''Ellipse Constructor - not sure of these, need to verify
#        def __init__(self, mx, my, rh, rv):
#        mx - center point x
#        my - center point y
#        rh - height of ellipse
#        rv - width of ellipse'''
#        x = self.INode.sceneBoundingRect().center().x()
#        y = self.INode.sceneBoundingRect().center().y()
#        w = self.INode.sceneBoundingRect().width()/2.0
#        h = self.INode.sceneBoundingRect().height()/2.0
#        myEllipse = Ellipse(x, y, w, h)
#        for d in range(0, 360, 10):
#            x, y = myEllipse.pointFromAngle(radians(d))
#            self.ellipsePoints.append([d, x, y])
#            aPoint = QGraphicsEllipseItem(QRectF(x-2.5,y-2.5,5, 5), parent=None)
#            self.ellipseGraphicItems.append(aPoint)
##        print(self.ellipsePoints)

    def formatItem(self, ):
        # configure the formatting aspects of the qgraphics item
        pen = self.nodeFormat.pen()
        brush = self.nodeFormat.brush()
        self.INode.setZValue(NODELAYER)
        self.INode.setBrush(brush)
        self.INode.setPen(pen)
        self.INode.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.INode.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
        self.INode.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.INode.setSelected(True)
        self.INode.setData(
            1, self.itemInstance.NZID)  # get with self.INode.data(1)
        self.INode.setData(ITEMTYPE, NODEINSTANCE)
        # draw the text
        self.updateText()
        self.INtext.setZValue(NODELAYER)
        self.INtext.setTextWidth(self.INode.boundingRect().width())
        self.INtext.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.INtext.setFlag(QGraphicsItem.ItemIsSelectable, False)
        self.INtext.setData(NODEID, self.itemInstance.NZID)
        self.INtext.setData(ITEMTYPE, NODEINSTANCETEXT)

    def updateText(self, ):
        '''
        Generate the HTML that formats the node  data inside the ellipse
        '''
        # generate the html
        prefix = "<!DOCTYPE html><html><body>"
        suffix = "</body></html>"
        try:
            Lbl = str(self.itemInstance.labelList[0][0])
        except:
            Lbl = "No Labels"
        firstLbl = "<center><b>{}</b></center>".format(Lbl)
        try:
            propName = str(self.itemInstance.propList[0][PROPERTY])
            propVal = str(self.itemInstance.propList[0][VALUE])
            prop = "{}: {}".format(propName, propVal)
        except:
            prop = "No Properties"
        firstProp = "<center>{}</center>".format(prop)
        genHTML = '{}{}<hr width="75%">{}{}'.format(prefix, firstLbl,
                                                    firstProp, suffix)
        self.INtext.setHtml(genHTML)

    def moveIt(self, dx, dy):
        '''Move the node ellipse and the node textbox to the delta x,y coordinate.'''
        #        print("before moveIt: sceneboundingrect {} ".format( self.INode.sceneBoundingRect()))

        self.INode.moveBy(dx, dy)
        self.x = self.INode.sceneBoundingRect().x()
        self.y = self.INode.sceneBoundingRect().y()
        self.INtext.moveBy(dx, dy)
        #        print("after moveIt: sceneboundingrect {} ".format( self.INode.sceneBoundingRect()))

        #        # recalc points
        #        self.genPoints()

        #        for point in self.ellipseGraphicItems:
        #            point.moveBy(dx, dy)

        self.moveRels()

    def moveRels(self, ):
        '''Redraw all the relationship arcs connected to the Node ellipse.'''
        #        print("moveRels")
        for key, diagramItem in self.scene.parent.itemDict.items():
            if diagramItem.diagramType == "Instance Relationship":
                if self.itemInstance.NZID in [
                        diagramItem.relationInstance.startNZID,
                        diagramItem.relationInstance.endNZID
                ]:
                    diagramItem.drawRelationship()
#                if diagramItem.relationInstance.startNZID == self.itemInstance.NZID:
#                    diagramItem.moveRelationshipLine()
##                    print("move startnode {}-{}".format(self.x, self.y))
#                if diagramItem.relationInstance.endNZID == self.itemInstance.NZID:
#                    diagramItem.moveRelationshipLine()
##                    print("move endnode {}-{}".format(self.x, self.y))

    def getObjectDict(self, ):
        '''
        This function returns a dictionary with all the data that represents this node item.  
        The dictionary is added to the Instance Diagram dictionary.'''
        objectDict = {}
        objectDict["NZID"] = self.itemInstance.NZID
        objectDict["x"] = self.INode.sceneBoundingRect().x()
        objectDict["y"] = self.INode.sceneBoundingRect().y()
        objectDict["diagramType"] = self.diagramType
        return objectDict

    def setLogMethod(self, logMethod=None):
        if logMethod is None:
            if self.logMsg is None:
                self.logMsg = self.noLog
        else:
            self.logMsg = logMethod

    def noLog(self, msg):
        return
예제 #6
0
class SegmentItemBase(QGraphicsItemGroup):
    def __init__(self, startNode, endNode, parent: "ConnectionBase"):
        """
        A connection is displayed as a chain of segmentItems (stored in Connection.segments)
        Parameters.
        ----------
        startNode
        endNode
        parent: type(parent): Connection
        """

        super().__init__(None)
        self.logger = parent.logger

        self.setFlag(self.ItemIsSelectable, True)

        self.dragged = False
        self.initialised = False
        self.connection = parent

        self.firstChild = None
        self.secondChild = None
        self.cornerChild = None

        self.linePoints = None

        self.startNode = startNode
        self.endNode = endNode

        # These nodes are the nodes before and after the crossing
        self.start = None
        self.end = None

        # Unused. Related to interrupting segments for a clearer diagram
        self.disrBeforeNode = None
        self.disrAfterNode = None
        self.disrBeforeSeg = None
        self.disrAfterSeg = None
        self.disrBefore = False
        self.disrAfter = False
        self.hasBridge = False
        self.bridgedSegment = None

        # Only for editorMode 1
        self.firstLine = None
        self.secondLine = None
        self.secondCorner = None
        self.thirdCorner = None

        self.keyPr = 0
        # Used to only create the child objects once
        self._isDraggingInProgress = False

        self.insertInParentSegments()

        self.label = QGraphicsTextItem(self.connection.displayName)
        self.connection.parent.diagramScene.addItem(self.label)
        self.label.setVisible(False)
        self.label.setFlag(self.ItemIsMovable, True)
        self.labelMass = QGraphicsTextItem()
        self.connection.parent.diagramScene.addItem(self.labelMass)
        self.labelMass.setVisible(False)
        self.labelMass.setFlag(self.ItemIsMovable, True)

        self.setToolTip(self.connection.displayName)

    def segLength(self):
        return calcDist(self.line().p1(), self.line().p2())

    def interpolate(
        self,
        partLen2,
        totLenConn,
    ):
        # c1_r = 0
        # c1_b = 255
        c1_r = 160
        c1_b = 160
        c1_g = 160

        # c2_r = 255
        # c2_b = 0
        c2_r = 0
        c2_b = 0
        c2_g = 0

        try:
            f1 = int(partLen2 / totLenConn)
            f2 = int((totLenConn - partLen2) / totLenConn)
        except ZeroDivisionError:
            return QColor(100, 100, 100)
        else:
            return QColor(f1 * c2_r + f2 * c1_r, f1 * c2_g + f2 * c1_g,
                          f1 * c2_b + f2 * c1_b)

    def line(self):
        return self.linePoints

    def setLine(self, *args):
        self.setZValue(-1)
        if len(args) == 2:
            p1, p2 = args
            x1 = p1.x()
            y1 = p1.y()
            x2 = p2.x()
            y2 = p2.y()
        else:
            x1, y1, x2, y2 = args

        self._setLineImpl(x1, y1, x2, y2)

    def _setLineImpl(self, x1, y1, x2, y2):
        raise NotImplementedError()

    def updateGrad(self):
        raise NotImplementedError()

    def insertInParentSegments(self):
        """
        This function inserts the segment in correct order to the segment list of the connection.
        Returns
        -------

        """
        prevSeg = None

        for s in self.connection.segments:
            if s.endNode is self.startNode:
                prevSeg = s

        # Todo: Add support for disr segments

        # if the startNode parent is a connection:
        if not hasattr(self.startNode.parent, "fromPort"):
            self.connection.segments.insert(
                self.connection.segments.index(prevSeg) + 1, self)
        else:

            self.connection.segments.insert(0, self)

    def mousePressEvent(self, e):

        if e.button() == 1:
            self.keyPr = 1
            self.logger.debug("Setting key to 1")

            self.connection.selectConnection()
            if self.isVertical():
                try:
                    self.oldX = self.startNode.parent.scenePos().x()
                except AttributeError:
                    pass
                else:
                    self.logger.debug("set oldx")

    def mouseMoveEvent(self, e):
        self.logger.debug(self.connection.parent.editorMode)
        if self.keyPr == 1:
            self.logger.debug("moved with button 1")
            newPos = e.pos()

            if self.connection.parent.editorMode == 0:
                if not self._isDraggingInProgress:
                    self.initInMode0()
                else:
                    self.dragInMode0(newPos)

            elif self.connection.parent.editorMode == 1:
                if type(self.startNode.parent) is CornerItem and type(
                        self.endNode.parent) is CornerItem:
                    if not self.startNode.parent.isVisible():
                        self.startNode.parent.setVisible(True)
                    if not self.endNode.parent.isVisible():
                        self.endNode.parent.setVisible(True)
                    if self.isVertical():

                        self.logger.debug("Segment is vertical: %s",
                                          self.connection.segments.index(self))
                        self.endNode.parent.setPos(
                            newPos.x(),
                            self.endNode.parent.scenePos().y())
                        self.startNode.parent.setPos(
                            newPos.x(),
                            self.startNode.parent.scenePos().y())
                        self.updateGrad()

                    if self.isHorizontal():
                        self.logger.debug("Segment is horizontal")
                        self.endNode.parent.setPos(
                            self.endNode.parent.scenePos().x(), newPos.y())
                        self.startNode.parent.setPos(
                            self.startNode.parent.scenePos().x(), newPos.y())

                elif type(self.endNode.parent
                          ) is CornerItem and self.isVertical():
                    self.logger.debug("Segment is vertical and can't be moved")

                if self.isHorizontal():
                    isFirstSegment = hasattr(
                        self.startNode.parent,
                        "fromPort") and not self.startNode.prevN()
                    isLastSegment = hasattr(
                        self.endNode.parent,
                        "fromPort") and not self.endNode.nextN()

                    if isLastSegment:
                        self.logger.debug("A last segment is being dragged.")
                        if not self._isDraggingInProgress:
                            self._initInMode1(False)
                        self._dragInMode1(False, newPos)
                    elif isFirstSegment:
                        self.logger.debug("A first segment is being dragged.")
                        if not self._isDraggingInProgress:
                            self._initInMode1(True)
                        self._dragInMode1(True, newPos)
            else:
                self.logger.debug(
                    "Unrecognized editorMode in segmentItem mouseMoveEvent")

    def deleteNextHorizSeg(self, b, nextS):
        if b:
            pass
        else:
            nodeTodelete1 = self.endNode
            nodeTodelete2 = self.endNode.nextN()
            self.endNode = nextS.endNode

            self.startNode.setNext(self.endNode)
            self.endNode.setPrev(self.startNode)

            # x-position of the ending point of the next segment line

            posx1 = self.connection.segments[
                self.connection.segments.index(self) + 2].line().p2().x()

            self.connection.parent.diagramScene.removeItem(nextS)
            self.connection.segments.remove(nextS)
            self.connection.parent.diagramScene.removeItem(
                nodeTodelete1.parent)

            indexOfSelf = self.connection.segments.index(self)
            nextVS = self.connection.segments[indexOfSelf + 1]

            self.connection.parent.diagramScene.removeItem(nextVS)
            self.connection.segments.remove(nextVS)
            self.connection.parent.diagramScene.removeItem(
                nodeTodelete2.parent)

            self.setLine(
                self.startNode.parent.scenePos().x(),
                self.startNode.parent.scenePos().y(),
                posx1,
                self.startNode.parent.scenePos().y(),
            )

    def deletePrevHorizSeg(self, b, prevS):
        if b:
            pass
        else:
            nodeTodelete1 = self.startNode
            nodeTodelete2 = self.startNode.prevN()
            self.startNode = prevS.startNode

            self.startNode.setNext(self.endNode)
            self.endNode.setPrev(self.startNode)

            posx1 = self.connection.segments[
                self.connection.segments.index(self) - 2].line().p1().x()

            self.connection.parent.diagramScene.removeItem(prevS)
            self.connection.segments.remove(prevS)
            self.connection.parent.diagramScene.removeItem(
                nodeTodelete1.parent)

            indexOfSelf = self.connection.segments.index(self)
            nextVS = self.connection.segments[indexOfSelf - 1]

            self.connection.parent.diagramScene.removeItem(nextVS)
            self.connection.segments.remove(nextVS)
            self.connection.parent.diagramScene.removeItem(
                nodeTodelete2.parent)

            self.setLine(
                posx1,
                self.endNode.parent.scenePos().y(),
                self.endNode.parent.scenePos().x(),
                self.endNode.parent.scenePos().y(),
            )

    def deleteSegment(self):
        nodeToConnect = self.startNode.prevN()
        nodeToConnect2 = self.endNode.nextN()

        nodeToConnect.setNext(nodeToConnect2)

        self.connection.parent.diagramScene.removeItem(self)
        self.connection.segments.remove(self)
        self.connection.parent.diagramScene.removeItem(self.startNode.parent)
        self.connection.parent.diagramScene.removeItem(self.endNode.parent)

    def splitSegment(self):
        pass

    def mouseReleaseEvent(self, e):
        # Should be same as below
        # self.scene().removeItem(self)

        if e.button() == 1:
            self.keyPr = 0

            if self.connection.parent.editorMode == 0:
                if self._isDraggingInProgress:
                    self.cornerChild.setFlag(
                        self.ItemSendsScenePositionChanges, True)

                    self.hide()
                    self.connection.segments.remove(self)
                    self.connection.parent.diagramScene.removeItem(self)

            elif self.connection.parent.editorMode == 1:
                if self.isVertical():
                    try:
                        self.oldX
                    except AttributeError:
                        pass
                    else:
                        command = HorizSegmentMoveCommand(
                            self, self.oldX, "Moving segment command")

                        self.connection.parent.parent().undoStack.push(command)
                        self.oldX = self.scenePos().x()

                if self.isHorizontal():
                    if type(self.startNode.parent) is CornerItem and type(
                            self.endNode.parent) is CornerItem:
                        try:

                            nextHorizSeg = self.connection.segments[
                                self.connection.segments.index(self) + 2]
                            prevHorizSeg = self.connection.segments[
                                self.connection.segments.index(self) - 2]
                        except IndexError:
                            self.logger.debug("no next or prev segments")
                        else:
                            if nextHorizSeg.isHorizontal(
                            ) and int(self.endNode.parent.pos().y() -
                                      10) <= int(nextHorizSeg.line().p2().y(
                                      )) <= int(self.endNode.parent.pos().y() +
                                                10):
                                self.deleteNextHorizSeg(False, nextHorizSeg)
                                self.logger.debug("next horizontal")
                                return

                            if prevHorizSeg.isHorizontal() and int(
                                    self.startNode.parent.pos().y() - 10
                            ) <= int(prevHorizSeg.line().p2().y()) <= int(
                                    self.startNode.parent.pos().y() + 10):
                                self.deletePrevHorizSeg(False, prevHorizSeg)
                                self.logger.debug("previous horizontal")
                                return

                if self.secondCorner is not None:
                    self.logger.debug("Second corner is not none")
                    # if PortItem
                    if hasattr(self.endNode.parent, "fromPort"):
                        segbef = self.connection.segments[
                            self.connection.getNodePos(
                                self.secondCorner.node.prevN().parent)]

                        segbef.setLine(
                            segbef.line().p1().x(),
                            segbef.line().p1().y(),
                            segbef.line().p2().x(),
                            self.secondCorner.scenePos().y(),
                        )
                        self.setLine(
                            self.thirdCorner.scenePos().x(),
                            self.thirdCorner.scenePos().y(),
                            self.line().p2().x(),
                            self.line().p2().y(),
                        )
                        self.secondCorner.setFlag(
                            self.ItemSendsScenePositionChanges, True)
                        self.thirdCorner.setFlag(
                            self.ItemSendsScenePositionChanges, True)

                        # Allow for iterative branching
                        self.secondCorner = None
                        self.thirdCorner = None
                        self.firstLine = None
                        self.secondLine = None
                        self._isDraggingInProgress = False

                    # if PortItem
                    elif hasattr(self.startNode.parent, "fromPort"):

                        segafter = self.connection.segments[
                            self.connection.getNodePos(
                                self.thirdCorner.node.nextN().parent)]

                        segafter.setLine(
                            segafter.line().p1().x(),
                            self.thirdCorner.scenePos().y(),
                            segafter.line().p2().x(),
                            segafter.line().p2().y(),
                        )
                        self.setLine(
                            self.line().p1().x(),
                            self.line().p1().y(),
                            self.secondCorner.scenePos().x(),
                            self.secondCorner.scenePos().y(),
                        )

                        self.secondCorner.setFlag(
                            self.ItemSendsScenePositionChanges, True)
                        self.thirdCorner.setFlag(
                            self.ItemSendsScenePositionChanges, True)

                        # Allow for iterative branching
                        self.secondCorner = None
                        self.thirdCorner = None
                        self.firstLine = None
                        self.secondLine = None
                        self._isDraggingInProgress = False

                    else:
                        self.logger.debug("getting no start or end")

                else:
                    self.logger.debug("Second corner is none")
            else:
                pass

    def initInMode0(self):
        if (hasattr(self.startNode.parent,
                    "fromPort")) and (self.startNode.prevN() is not None):
            self.disrAfterNode = self.startNode
            self.start = self.startNode.prevN().prevN()

            segments = self.connection.segments
            for s in segments:
                if s.startNode is self.start:
                    self.disrBeforeSeg = s

            self.disrAfterSeg = self
            self.disrBefore = True

        else:
            self.start = self.startNode

        if (hasattr(self.endNode.parent,
                    "fromPort")) and (self.endNode.nextN() is not None):
            self.disrBeforeNode = self.endNode
            self.end = self.endNode.nextN().nextN()

            segments = self.connection.segments
            for s in segments:
                if s.endNode is self.end:
                    self.disrAfterSeg = s

            self.disrBeforeSeg = self
            self.disrAfter = True

        else:
            self.end = self.endNode

        rad = self.connection.getRadius()

        self.cornerChild = CornerItem(-rad, -rad, 2 * rad, 2 * rad, self.start,
                                      self.end, self.connection)
        self.firstChild = self._createSegment(self.start,
                                              self.cornerChild.node)
        self.secondChild = self._createSegment(self.cornerChild.node, self.end)

        self.start.setNext(self.cornerChild.node)
        self.end.setPrev(self.cornerChild.node)

        self.firstChild.setVisible(False)
        self.secondChild.setVisible(False)
        self.cornerChild.setVisible(False)

        self.connection.parent.diagramScene.addItem(self.firstChild)
        self.connection.parent.diagramScene.addItem(self.secondChild)
        self.connection.parent.diagramScene.addItem(self.cornerChild)

        self._isDraggingInProgress = True

    def _initInMode1(self, b):

        rad = self.connection.getRadius()

        if b:
            if (hasattr(self.startNode.parent,
                        "fromPort")) and (self.startNode.prevN() is None):
                # We are at the toPort.
                # self.end = self.endNode
                # self.start = self.startNode

                self.secondCorner = CornerItem(-rad, -rad, 2 * rad, 2 * rad,
                                               self.startNode, None,
                                               self.connection)
                self.thirdCorner = CornerItem(-rad, -rad, 2 * rad, 2 * rad,
                                              self.secondCorner.node,
                                              self.endNode, self.connection)

                self.secondCorner.node.setNext(self.thirdCorner.node)
                self.startNode.setNext(self.secondCorner.node)
                self.endNode.setPrev(self.thirdCorner.node)

                self.endNode = self.secondCorner.node

                self.firstLine = self._createSegment(self.secondCorner.node,
                                                     self.thirdCorner.node)
                self.secondLine = self._createSegment(
                    self.thirdCorner.node, self.thirdCorner.node.nextN())

                self.secondCorner.setVisible(False)
                self.thirdCorner.setVisible(False)
                self.firstLine.setVisible(False)
                self.secondLine.setVisible(False)
                # self.thirdLine.setVisible(False)

                self.connection.parent.diagramScene.addItem(self.secondCorner)
                self.connection.parent.diagramScene.addItem(self.thirdCorner)
                self.connection.parent.diagramScene.addItem(self.firstLine)
                self.connection.parent.diagramScene.addItem(self.secondLine)
                self.logger.debug("inited")

                self._isDraggingInProgress = True
        else:
            if (hasattr(self.endNode.parent,
                        "fromPort")) and (self.endNode.nextN() is None):
                # We are at the toPort.
                # self.end = self.endNode
                # self.start = self.startNode

                self.secondCorner = CornerItem(-rad, -rad, 2 * rad, 2 * rad,
                                               self.startNode, None,
                                               self.connection)
                self.thirdCorner = CornerItem(-rad, -rad, 2 * rad, 2 * rad,
                                              self.secondCorner.node,
                                              self.endNode, self.connection)

                self.secondCorner.node.setNext(self.thirdCorner.node)
                self.startNode.setNext(self.secondCorner.node)
                self.endNode.setPrev(self.thirdCorner.node)

                self.startNode = self.thirdCorner.node

                self.firstLine = self._createSegment(
                    self.secondCorner.node.prevN(), self.secondCorner.node)
                self.secondLine = self._createSegment(self.secondCorner.node,
                                                      self.thirdCorner.node)

                self.secondCorner.setVisible(False)
                self.thirdCorner.setVisible(False)
                self.firstLine.setVisible(False)
                self.secondLine.setVisible(False)
                # self.thirdLine.setVisible(False)

                self.connection.parent.diagramScene.addItem(self.secondCorner)
                self.connection.parent.diagramScene.addItem(self.thirdCorner)
                self.connection.parent.diagramScene.addItem(self.firstLine)
                self.connection.parent.diagramScene.addItem(self.secondLine)
                self.logger.debug("inited")

                self._isDraggingInProgress = True

    def _createSegment(self, startNode, endNode) -> "SegmentItemBase":
        raise NotImplementedError()

    def isVertical(self):
        return self.line().p1().x() == self.line().p2().x()

    def isHorizontal(self):
        return self.line().p1().y() == self.line().p2().y()

    def dragInMode0(self, newPos):
        p1 = self.line().p1()
        p2 = self.line().p2()

        if len(self.scene().items(newPos)) == 0:

            self.firstChild.setLine(p1.x(), p1.y(), newPos.x(), newPos.y())
            self.secondChild.setLine(newPos.x(), newPos.y(), p2.x(), p2.y())

            self.cornerChild.setPos(newPos)

            self.firstChild.updateGrad()
            self.secondChild.updateGrad()

            # Bring corner to front
            self.cornerChild.setZValue(100)
            self.firstChild.setZValue(1)
            self.secondChild.setZValue(1)

            self.firstChild.setVisible(True)
            self.secondChild.setVisible(True)
            self.cornerChild.setVisible(True)

    def _dragInMode1(self, b, newPos):
        self.logger.debug("after inited")

        if b:
            self.thirdCorner.setPos(newPos.x() - 10, newPos.y())

            self.secondCorner.setPos(newPos.x() - 10,
                                     self.connection.fromPort.scenePos().y())
            self.thirdCorner.node.nextN().parent.setY(newPos.y())

            self.firstLine.setLine(
                self.secondCorner.scenePos().x(),
                self.secondCorner.scenePos().y(),
                self.thirdCorner.scenePos().x(),
                newPos.y(),
            )
            self.secondLine.setLine(
                self.thirdCorner.scenePos().x(),
                self.thirdCorner.scenePos().y(),
                self.thirdCorner.node.nextN().parent.scenePos().x(),
                self.thirdCorner.node.nextN().parent.scenePos().y(),
            )
            self.setLine(
                self.startNode.parent.fromPort.scenePos().x(),
                self.startNode.parent.fromPort.scenePos().y(),
                self.secondCorner.scenePos().x(),
                self.secondCorner.scenePos().y(),
            )

            self.secondCorner.setZValue(100)
            self.thirdCorner.setZValue(100)
            self.firstLine.setZValue(1)
            self.secondLine.setZValue(1)

            self.secondCorner.setVisible(True)
            self.thirdCorner.setVisible(True)
            self.firstLine.setVisible(True)
            self.secondLine.setVisible(True)

        else:
            self.secondCorner.setPos(newPos.x() + 10, newPos.y())

            self.thirdCorner.setPos(newPos.x() + 10,
                                    self.connection.toPort.scenePos().y())
            self.secondCorner.node.prevN().parent.setY(newPos.y())

            self.firstLine.setLine(
                self.secondCorner.node.prevN().parent.scenePos().x(),
                newPos.y(),
                self.secondCorner.scenePos().x(),
                newPos.y(),
            )
            self.secondLine.setLine(
                self.secondCorner.scenePos().x(),
                self.secondCorner.scenePos().y(),
                self.thirdCorner.scenePos().x(),
                self.thirdCorner.scenePos().y(),
            )
            self.setLine(
                self.thirdCorner.scenePos().x(),
                self.thirdCorner.scenePos().y(),
                self.endNode.parent.toPort.scenePos().x(),
                self.endNode.parent.toPort.scenePos().y(),
            )

            self.secondCorner.setZValue(100)
            self.thirdCorner.setZValue(100)
            self.firstLine.setZValue(1)
            self.secondLine.setZValue(1)

            self.secondCorner.setVisible(True)
            self.thirdCorner.setVisible(True)
            self.firstLine.setVisible(True)
            self.secondLine.setVisible(True)

    def renameConn(self):
        self.scene().parent().showSegmentDlg(self)

    def printItemsAt(self):
        self.logger.debug("Items at startnode are %s",
                          str(self.scene().items(self.line().p1())))
        self.logger.debug("Items at endnode are %s",
                          str(self.scene().items(self.line().p2())))

        for s in self.connection.segments:
            self.logger.debug(
                "Segment in list is %s has startnode %s endnode %s",
                str(s),
                str(s.startNode.parent),
                str(s.endNode.parent),
            )

    def contextMenuEvent(self, event):
        menu = self._getContextMenu()

        menu.exec(event.screenPos())

    def _getContextMenu(self) -> QMenu:
        menu = QMenu()
        a1 = menu.addAction("Rename...")
        a1.triggered.connect(self.renameConn)
        a2 = menu.addAction("Delete this connection")
        a2.triggered.connect(
            self.connection.createDeleteUndoCommandAndAddToStack)
        a3 = menu.addAction("Invert this connection")
        a3.triggered.connect(self.connection.invertConnection)
        a4 = menu.addAction("Toggle name")
        a4.triggered.connect(self.connection.toggleLabelVisible)
        a5 = menu.addAction("Toggle mass flow")
        a5.triggered.connect(self.connection.toggleMassFlowLabelVisible)
        return menu

    def setLabelVisible(self, isVisible: bool) -> None:
        self.label.setVisible(isVisible)

    def toggleLabelVisible(self) -> None:
        wasVisible = self.label.isVisible()
        self.setLabelVisible(not wasVisible)

    def setMassFlowLabelVisible(self, isVisible: bool) -> None:
        self.labelMass.setVisible(isVisible)

    def toggleMassFlowLabelVisible(self) -> None:
        wasVisible = self.labelMass.isVisible()
        self.setMassFlowLabelVisible(not wasVisible)

    def setSelect(self, isSelected: bool) -> None:
        raise NotImplementedError()

    @staticmethod
    def _createSelectPen() -> QPen:
        color = QColor(125, 242, 189)
        width = 4

        selectPen = QPen(color, width)
        return selectPen

    def setColorAndWidthAccordingToMassflow(self, color, width):
        raise NotImplementedError()