mscGraphMessage.py 9.06 KB
Newer Older
Maxime Perrotin's avatar
Maxime Perrotin committed
1 2 3 4 5 6 7 8
#******************************************************************************
#
# TASTE Msc Diagram Editor
# http://taste.tuxfamily.org/
#
#  This file is part of TASTE Msc Editor.
#
#  TASTE Msc Diagram Editor is free software: you can redistribute it and/or
Maxime Perrotin's avatar
Maxime Perrotin committed
9
#  modify it under the terms of the GNU Lesser General Public License as published
Maxime Perrotin's avatar
Maxime Perrotin committed
10 11 12 13 14 15
#  by the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  TASTE Msc Diagram Editor is distributed in the hope that it will be
#  useful,(but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Maxime Perrotin's avatar
Maxime Perrotin committed
16
#  GNU Lesser General Public License for more details.
Maxime Perrotin's avatar
Maxime Perrotin committed
17
#
Maxime Perrotin's avatar
Maxime Perrotin committed
18
#  You should have received a copy of the GNU Lesser General Public License
Maxime Perrotin's avatar
Maxime Perrotin committed
19 20 21 22 23
#  along with TASTE Msc Diagram Editor.  If not, see
#  <http://www.gnu.org/licenses/>.
#
#  Author: Angel Esquinas <aesquina@datsi.fi.upm.es>
#
Maxime Perrotin's avatar
Maxime Perrotin committed
24
#  Copyright (c) 2012 UPM and European Space Agency
Maxime Perrotin's avatar
Maxime Perrotin committed
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
#
#******************************************************************************
from PySide.QtCore import Qt, QPointF, Slot
from PySide.QtGui import QColor, QPen

import msccore

from mscgraphics import MscGraphItem
from mscgraphics import MscLabelable
from mscArrowHead import MscArrowHead


class MscGraphMessage(MscGraphItem):
    '''
    MSCGraphMessage is graphical class that represent
    an message between two instances
    '''
    ArrowSize = 20
    ArrowColor = QColor(Qt.blue)
    ZVALUE = 1000

    def __init__(self, startInstance=None, endInstance=None,
                 y=0, label=None, data=None, parent=None):

        super(MscGraphMessage, self).__init__(parent)

        self.mesSender = startInstance
        self.mesReceiver = endInstance
        self.complete = False

        if label == None:
            label = "Message"

        if data == None:
            self.setMscData(msccore.MscMessage(start=self.mesSender.mscData(),
                                           end=self.mesReceiver.mscData(),
                                           name=label))
        else:
            self.setMscData(data)

        # Message Text
        self.addMessageText()
        # Flag to know if the message are the Left to Right
        self.LTR = True

        self.setPos(self.pos().x(), y)
        self.setZValue(self.ZVALUE)
        self.instanceMove = False

        self.initilizeGraphics()

        #Item Properties: Movable
        self.setFlag(MscGraphItem.ItemIsMovable, True)
        # Message signal when selected
        self.setSignalWhenSelected(True)

        # Instances of Message
        if startInstance != None:
            self.setStartInstance(startInstance)
        if endInstance != None:
            self.setEndInstance(endInstance)

    def setStartInstance(self, inst):
        self.mesSender = inst
        inst.addMessageEvent(self)
        inst.xChanged.connect(self.updatePosition)
        if self.mesReceiver != None:
            self.updatePosition()
            self.resetMessagePos()

    def setEndInstance(self, inst):
        self.mesReceiver = inst
        inst.addMessageEvent(self)
        inst.xChanged.connect(self.updatePosition)
        if self.mesSender != None:
            self.updatePosition()
            self.resetMessagePos()

    #**************************************************************************
    # CORE DATA
    #**************************************************************************
    @Slot(str)
    def setDataName(self,name):
        self.mscData().setName(name)

    @Slot()
    def readMscData(self):
        self.updateMessageText()
        super(MscGraphMessage, self).readMscData()

    def delete(self):
        # It can be changed for eliminate the event
        if self.mesSender != None:
            self.mesSender.removeMessageEvent(self)
            self.mesSender = None
        if self.mesReceiver != None:
            self.mesReceiver.removeMessageEvent(self)
            self.mesReceiver = None
        self.mscData().delete()
        self.setParentItem(None)
        #self.deleteLater()

    #**************************************************************************
    # Message Text
    #**************************************************************************
    def midCoordenate(self):
        return QPointF(self.width / 2.0, 0)

    def addMessageText(self):
        self.messageText = MscLabelable(self.mscData().textual(),
                                        self)
        self.messageText.setFlag(MscLabelable.ItemIsMovable, True)
        self.mesDX = 0
        self.mesDY = -10
        self.updateMessageText()
        self.messageText.labelPositionChanged.connect(self.updateMessageDelta)
        self.messageText.labelChanged.connect(self.setDataName)

    def resetMessagePos(self):
        self.mesDX = 0
        self.mesDY = -10
        c = self.midCoordenate()
        c.setX(c.x() + self.mesDX)
        c.setY(c.y() + self.mesDY)
        self.messageText.setCenterPos(c)

    def updateMessageTextPos(self):
        c = self.midCoordenate()
        c.setX(c.x() + self.mesDX)
        c.setY(c.y() + self.mesDY)
        self.messageText.setCenterPos(c)

    def updateMessageDelta(self, pos):
        self.mesDX = pos.x() - self.midCoordenate().x()
        self.mesDY = pos.y()

    def textMessageChange(self, text):
        self.Name = text

    def updateMessageText(self):
        self.messageText.setTextLabel(self.mscData().textual())

    #**************************************************************************
    # Comment Position
    #**************************************************************************
    def commentPosition(self):
        return QPointF(self.width, 0)

    #**************************************************************************
    # Initialize Graphical Variables
    #**************************************************************************
    def initilizeGraphics(self):
        # Paint Options
        self.color = self.ArrowColor
        self.pen = QPen(self.color, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)

        # Arrow of Message
        self.arrowHead = MscArrowHead(self)
        self.arrowHead.setColor(self.color)

        # Where are the message. TODO Reimplement setPos() of message
        self.drawOriginX = 0
        self.drawOriginY = self.arrowHead.boundingRect().y()
        if self.mesReceiver != None:
            self.width = self.mesReceiver.pos().x() - self.pos().x()
        self.height = self.arrowHead.boundingRect().height()

    #**************************************************************************
    # Item Change
    #**************************************************************************
    def limitsOfInstance(self, value):
        # startItem Positions
        sendStart = self.mesSender.upperLimitInstance(True)
        sendEnd = self.mesSender.bottomLimitInstance(True)
        # endItem Positions
        recvStart = self.mesReceiver.upperLimitInstance(False)
        recvEnd = self.mesReceiver.bottomLimitInstance(False)

        # Message are not above the instances
        if value.y() < sendStart.y():
            value.setY(sendStart.y())
        if value.y() < recvStart.y():
            value.setY(recvStart.y())

        value.setX(self.pos().x())
        return value

    # If change position, repaint messages
    def itemChange(self, change, value):
        if (change == MscGraphItem.ItemPositionChange and
            self.instanceMove == False):
            value = self.limitsOfInstance(value)
            return MscGraphItem.itemChange(self, change, value)

        elif (change == super(MscGraphMessage, self).ItemPositionHasChanged):
            self.mscData().setAbsPos(self.mapToScene(0, 0).y())
            self.yHasChanged.emit(self)

        self.instanceMove = False
        return MscGraphItem.itemChange(self, change, value)

    #**************************************************************************
    # Update Graphics Functions
    #**************************************************************************
    def updatePosArrow(self):
        self.arrowHead.setPos(self.width, 0)
        if ((self.width < 0 and self.LTR) or
            (self.width > 0 and not self.LTR)):
            self.arrowHead.scale(-1, 1)
            self.LTR = not self.LTR

    def updatePosition(self):
        ''' Update message position when associated instance is move '''
        startItem = self.mesSender
        endItem = self.mesReceiver

        self.instanceMove = True
        self.prepareGeometryChange()
        mypos = self.limitsOfInstance(self.pos())
        self.setPos(startItem.upperLimitInstance(True).x(),
                    mypos.y())
        self.width = (endItem.upperLimitInstance(False).x()
                      - startItem.upperLimitInstance(True).x())
        self.updateMessageTextPos()
        self.updatePosArrow()
        self.itemResized.emit()

    #**************************************************************************
    # Paint Functions
    #**************************************************************************
    def paint(self, painter, option, widget=None):
        painter.setPen(self.pen)
        painter.drawLine(QPointF(0, 0), QPointF(self.width, 0))