You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdesdk/umbrello/umbrello/messagewidget.cpp

793 lines
25 KiB

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* copyright (C) 2002-2007 *
* Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
***************************************************************************/
// onw header
#include "messagewidget.h"
//qt includes
#include <tqpainter.h>
//kde includes
#include <kdebug.h>
#include <kcursor.h>
//app includes
#include "messagewidgetcontroller.h"
#include "floatingtextwidget.h"
#include "objectwidget.h"
#include "classifier.h"
#include "operation.h"
#include "umlview.h"
#include "umldoc.h"
#include "uml.h"
#include "uniqueid.h"
#include "listpopupmenu.h"
MessageWidget::MessageWidget(UMLView * view, ObjectWidget* a, ObjectWidget* b,
int y, Uml::Sequence_Message_Type sequenceMessageType,
Uml::IDType id /* = Uml::id_None */)
: UMLWidget(view, id, new MessageWidgetController(this)) {
init();
m_pOw[Uml::A] = a;
m_pOw[Uml::B] = b;
m_nY = y;
m_sequenceMessageType = sequenceMessageType;
if (m_sequenceMessageType == Uml::sequence_message_creation) {
y -= m_pOw[Uml::B]->getHeight() / 2;
m_pOw[Uml::B]->setY(y);
}
updateResizability();
calculateWidget();
y = y < getMinY() ? getMinY() : y;
y = y > getMaxY() ? getMaxY() : y;
m_nY = y;
this->activate();
}
MessageWidget::MessageWidget(UMLView * view, Uml::Sequence_Message_Type seqMsgType, Uml::IDType id)
: UMLWidget(view, id, new MessageWidgetController(this)) {
init();
m_sequenceMessageType = seqMsgType;
}
void MessageWidget::init() {
UMLWidget::setBaseType(Uml::wt_Message);
m_bIgnoreSnapToGrid = true;
m_bIgnoreSnapComponentSizeToGrid = true;
m_pOw[Uml::A] = m_pOw[Uml::B] = NULL;
m_pFText = NULL;
m_nY = 0;
setVisible(true);
}
MessageWidget::~MessageWidget() {
}
void MessageWidget::updateResizability() {
if (m_sequenceMessageType == Uml::sequence_message_synchronous ||
m_pOw[Uml::A] == m_pOw[Uml::B])
UMLWidget::m_bResizable = true;
else
UMLWidget::m_bResizable = false;
}
void MessageWidget::draw(TQPainter& p, int offsetX, int offsetY) {
if(!m_pOw[Uml::A] || !m_pOw[Uml::B]) {
return;
}
UMLWidget::setPen(p);
if (m_sequenceMessageType == Uml::sequence_message_synchronous) {
drawSynchronous(p, offsetX, offsetY);
} else if (m_sequenceMessageType == Uml::sequence_message_asynchronous) {
drawAsynchronous(p, offsetX, offsetY);
} else if (m_sequenceMessageType == Uml::sequence_message_creation) {
drawCreation(p, offsetX, offsetY);
} else {
kWarning() << "Unknown message type" << endl;
}
}
void MessageWidget::drawSolidArrowhead(TQPainter& p, int x, int y, TQt::ArrowType direction) {
int arrowheadExtentX = 4;
if (direction == TQt::RightArrow) {
arrowheadExtentX = -arrowheadExtentX;
}
TQPointArray points;
points.putPoints(0, 3, x, y, x + arrowheadExtentX, y - 3, x + arrowheadExtentX, y + 3);
p.setBrush( TQBrush(p.pen().color()) );
p.drawPolygon(points);
}
void MessageWidget::drawArrow(TQPainter& p, int x, int y, int w,
TQt::ArrowType direction, bool useDottedLine /* = false */) {
int arrowheadStartX = x;
int arrowheadExtentX = 4;
if (direction == TQt::RightArrow) {
arrowheadStartX += w;
arrowheadExtentX = -arrowheadExtentX;
}
// draw upper half of arrowhead
p.drawLine(arrowheadStartX, y, arrowheadStartX + arrowheadExtentX, y - 3);
// draw lower half of arrowhead
p.drawLine(arrowheadStartX, y, arrowheadStartX + arrowheadExtentX, y + 3);
// draw arrow line
if (useDottedLine) {
TQPen pen = p.pen();
pen.setStyle(TQt::DotLine);
p.setPen(pen);
}
p.drawLine(x, y, x + w, y);
}
void MessageWidget::drawSynchronous(TQPainter& p, int offsetX, int offsetY) {
int x1 = m_pOw[Uml::A]->getX();
int x2 = m_pOw[Uml::B]->getX();
int w = getWidth() - 1;
int h = getHeight();
bool messageOverlaps = m_pOw[Uml::A] -> messageOverlap( getY(), this );
if(m_pOw[Uml::A] == m_pOw[Uml::B]) {
p.fillRect( offsetX, offsetY, 17, h, TQBrush(TQt::white) ); //box
p.drawRect(offsetX, offsetY, 17, h); //box
offsetX += 17;
w -= 17;
offsetY += 3;
const int lowerLineY = offsetY + h - 6;
// draw upper line segment (leaving the life line)
p.drawLine(offsetX, offsetY, offsetX + w, offsetY);
// draw line segment parallel to (and at the right of) the life line
p.drawLine(offsetX + w, offsetY, offsetX + w, lowerLineY);
// draw lower line segment (back to the life line)
drawArrow(p, offsetX, lowerLineY, w, TQt::LeftArrow);
offsetX -= 17;
offsetY -= 3;
} else if(x1 < x2) {
if (messageOverlaps) {
offsetX += 8;
w -= 8;
}
TQPen pen = p.pen();
int startX = offsetX + w - 16;
p.fillRect(startX, offsetY, 17, h, TQBrush(TQt::white)); //box
p.drawRect(startX, offsetY, 17, h); //box
p.drawLine(offsetX, offsetY + 4, startX, offsetY + 4); //arrow line
drawSolidArrowhead(p, startX - 1, offsetY + 4, TQt::RightArrow);
drawArrow(p, offsetX, offsetY + h - 3, w - 16, TQt::LeftArrow, true); // return arrow
if (messageOverlaps) {
offsetX -= 8; //reset for drawSelected()
}
} else {
if (messageOverlaps) {
w -=8;
}
TQPen pen = p.pen();
p.fillRect( offsetX, offsetY, 17, h, TQBrush(TQt::white) ); //box
p.drawRect(offsetX, offsetY, 17, h); //box
p.drawLine(offsetX + 18, offsetY + 4, offsetX + w, offsetY + 4); //arrow line
drawSolidArrowhead(p, offsetX + 17, offsetY + 4, TQt::LeftArrow);
drawArrow(p, offsetX + 18, offsetY + h - 3, w - 18, TQt::RightArrow, true); // return arrow
}
if(m_bSelected) {
drawSelected(&p, offsetX, offsetY);
}
}
void MessageWidget::drawAsynchronous(TQPainter& p, int offsetX, int offsetY) {
int x1 = m_pOw[Uml::A]->getX();
int x2 = m_pOw[Uml::B]->getX();
int w = getWidth() - 1;
int h = getHeight() - 1;
bool messageOverlapsA = m_pOw[Uml::A] -> messageOverlap( getY(), this );
//bool messageOverlapsB = m_pOw[Uml::B] -> messageOverlap( getY(), this );
if(m_pOw[Uml::A] == m_pOw[Uml::B]) {
if (messageOverlapsA) {
offsetX += 7;
w -= 7;
}
const int lowerLineY = offsetY + h - 3;
// draw upper line segment (leaving the life line)
p.drawLine(offsetX, offsetY, offsetX + w, offsetY);
// draw line segment parallel to (and at the right of) the life line
p.drawLine(offsetX + w, offsetY, offsetX + w, lowerLineY);
// draw lower line segment (back to the life line)
drawArrow(p, offsetX, lowerLineY, w, TQt::LeftArrow);
if (messageOverlapsA) {
offsetX -= 7; //reset for drawSelected()
}
} else if(x1 < x2) {
if (messageOverlapsA) {
offsetX += 7;
w -= 7;
}
drawArrow(p, offsetX, offsetY + 4, w, TQt::RightArrow);
if (messageOverlapsA) {
offsetX -= 7;
}
} else {
if (messageOverlapsA) {
w -= 7;
}
drawArrow(p, offsetX, offsetY + 4, w, TQt::LeftArrow);
}
if (m_bSelected)
drawSelected(&p, offsetX, offsetY);
}
void MessageWidget::drawCreation(TQPainter& p, int offsetX, int offsetY) {
int x1 = m_pOw[Uml::A]->getX();
int x2 = m_pOw[Uml::B]->getX();
int w = getWidth() - 1;
//int h = getHeight() - 1;
bool messageOverlapsA = m_pOw[Uml::A] -> messageOverlap( getY(), this );
//bool messageOverlapsB = m_pOw[Uml::B] -> messageOverlap( getY(), this );
const int lineY = offsetY + 4;
if (x1 < x2) {
if (messageOverlapsA) {
offsetX += 7;
w -= 7;
}
drawArrow(p, offsetX, lineY, w, TQt::RightArrow);
if (messageOverlapsA) {
offsetX -= 7;
}
} else {
if (messageOverlapsA) {
w -= 7;
}
drawArrow(p, offsetX, lineY, w, TQt::LeftArrow);
}
if (m_bSelected)
drawSelected(&p, offsetX, offsetY);
}
int MessageWidget::onWidget(const TQPoint & p) {
if (m_sequenceMessageType != Uml::sequence_message_synchronous) {
return UMLWidget::onWidget(p);
}
// Synchronous message:
// Consists of top arrow (call) and bottom arrow (return.)
if (p.x() < getX() || p.x() > getX() + getWidth())
return 0;
const int tolerance = 5; // pixels
const int pY = p.y();
const int topArrowY = getY() + 3;
const int bottomArrowY = getY() + getHeight() - 3;
if (pY < topArrowY - tolerance || pY > bottomArrowY + tolerance)
return 0;
if (getHeight() <= 2 * tolerance)
return 1;
if (pY > topArrowY + tolerance && pY < bottomArrowY - tolerance)
return 0;
return 1;
}
void MessageWidget::setTextPosition() {
if (m_pFText == NULL) {
kDebug() << "MessageWidget::setTextPosition: m_pFText is NULL"
<< endl;
return;
}
if (m_pFText->getDisplayText().isEmpty()) {
return;
}
m_pFText->updateComponentSize();
int ftX = constrainX(m_pFText->getX(), m_pFText->getWidth(), m_pFText->getRole());
int ftY = getY() - m_pFText->getHeight();
m_pFText->setX( ftX );
m_pFText->setY( ftY );
}
int MessageWidget::constrainX(int textX, int textWidth, Uml::Text_Role tr) {
int result = textX;
const int minTextX = getX() + 5;
if (textX < minTextX || tr == Uml::tr_Seq_Message_Self) {
result = minTextX;
} else {
ObjectWidget *objectAtRight = NULL;
if (m_pOw[Uml::B]->getX() > m_pOw[Uml::A]->getX())
objectAtRight = m_pOw[Uml::B];
else
objectAtRight = m_pOw[Uml::A];
const int objRight_seqLineX = objectAtRight->getX() + objectAtRight->getWidth() / 2;
const int maxTextX = objRight_seqLineX - textWidth - 5;
if (maxTextX <= minTextX)
result = minTextX;
else if (textX > maxTextX)
result = maxTextX;
}
return result;
}
void MessageWidget::constrainTextPos(int &textX, int &textY, int textWidth, int textHeight,
Uml::Text_Role tr) {
textX = constrainX(textX, textWidth, tr);
// Constrain Y.
const int minTextY = getMinY();
const int maxTextY = getMaxY() - textHeight - 5;
if (textY < minTextY)
textY = minTextY;
else if (textY > maxTextY)
textY = maxTextY;
// setY( textY + textHeight ); // NB: side effect
}
void MessageWidget::setLinkAndTextPos() {
if (m_pFText == NULL)
return;
m_pFText->setLink(this);
setTextPosition();
}
void MessageWidget::moveEvent(TQMoveEvent* /*m*/) {
//kDebug() << "MessageWidget::moveEvent: m_pFText is " << m_pFText << endl;
if (!m_pFText) {
return;
}
//TODO why this condition?
/* if (m_pView->getSelectCount() > 2) {
return;
}*/
setTextPosition();
emit sigMessageMoved();
}
void MessageWidget::resizeEvent(TQResizeEvent* /*re*/) {
}
void MessageWidget::calculateWidget() {
setMessageText(m_pFText);
calculateDimensions();
setVisible(true);
setX(m_nPosX);
setY(m_nY);
}
void MessageWidget::slotWidgetMoved(Uml::IDType id) {
const Uml::IDType idA = m_pOw[Uml::A]->getLocalID();
const Uml::IDType idB = m_pOw[Uml::B]->getLocalID();
if (idA != id && idB != id) {
kDebug() << "MessageWidget::slotWidgetMoved(" << ID2STR(id)
<< "): ignoring for idA=" << ID2STR(idA)
<< ", idB=" << ID2STR(idB) << endl;
return;
}
m_nY = getY();
if (m_nY < getMinY())
m_nY = getMinY();
if (m_nY > getMaxY())
m_nY = getMaxY();
calculateWidget();
if( !m_pFText )
return;
if (m_pView->getSelectCount(true) > 1)
return;
setTextPosition();
}
bool MessageWidget::contains(ObjectWidget * w) {
if(m_pOw[Uml::A] == w || m_pOw[Uml::B] == w)
return true;
else
return false;
}
void MessageWidget::slotMenuSelection(int sel) {
if(sel == ListPopupMenu::mt_Delete) {
// This will clean up this widget and the text widget:
m_pView -> removeWidget(this);
} else {
if (m_pFText == NULL) {
Uml::Text_Role tr = Uml::tr_Seq_Message;
if (m_pOw[Uml::A] == m_pOw[Uml::B])
tr = Uml::tr_Seq_Message_Self;
m_pFText = new FloatingTextWidget( m_pView, tr );
m_pFText->setFont(UMLWidget::getFont());
setLinkAndTextPos();
m_pView->getWidgetList().append(m_pFText);
}
m_pFText -> slotMenuSelection(sel);
}
}
bool MessageWidget::activate(IDChangeLog * Log /*= 0*/) {
m_pView->resetPastePoint();
// UMLWidget::activate(Log); CHECK: I don't think we need this ?
if (m_pOw[Uml::A] == NULL) {
UMLWidget *pWA = m_pView->findWidget(m_widgetAId);
if (pWA == NULL) {
kDebug() << "MessageWidget::activate: role A object "
<< ID2STR(m_widgetAId) << " not found" << endl;
return false;
}
m_pOw[Uml::A] = dynamic_cast<ObjectWidget*>(pWA);
if (m_pOw[Uml::A] == NULL) {
kDebug() << "MessageWidget::activate: role A widget "
<< ID2STR(m_widgetAId) << " is not an ObjectWidget" << endl;
return false;
}
}
if (m_pOw[Uml::B] == NULL) {
UMLWidget *pWB = m_pView->findWidget(m_widgetBId);
if (pWB == NULL) {
kDebug() << "MessageWidget::activate: role B object "
<< ID2STR(m_widgetBId) << " not found" << endl;
return false;
}
m_pOw[Uml::B] = dynamic_cast<ObjectWidget*>(pWB);
if (m_pOw[Uml::B] == NULL) {
kDebug() << "MessageWidget::activate: role B widget "
<< ID2STR(m_widgetBId) << " is not an ObjectWidget" << endl;
return false;
}
}
updateResizability();
UMLClassifier *c = dynamic_cast<UMLClassifier*>(m_pOw[Uml::B]->getUMLObject());
UMLOperation *op = NULL;
if (c && !m_CustomOp.isEmpty()) {
Uml::IDType opId = STR2ID(m_CustomOp);
op = dynamic_cast<UMLOperation*>( c->findChildObjectById(opId, true) );
if (op) {
// If the UMLOperation is set, m_CustomOp isn't used anyway.
// Just setting it empty for the sake of sanity.
m_CustomOp = TQString();
}
}
if( !m_pFText ) {
Uml::Text_Role tr = Uml::tr_Seq_Message;
if (m_pOw[Uml::A] == m_pOw[Uml::B])
tr = Uml::tr_Seq_Message_Self;
m_pFText = new FloatingTextWidget( m_pView, tr, "" );
m_pFText->setFont(UMLWidget::getFont());
}
if (op)
setOperation(op); // This requires a valid m_pFText.
setLinkAndTextPos();
m_pFText -> setText("");
m_pFText->setActivated();
TQString messageText = m_pFText->getText();
m_pFText->setVisible( messageText.length() > 1 );
connect(m_pOw[Uml::A], TQ_SIGNAL(sigWidgetMoved(Uml::IDType)), this, TQ_SLOT(slotWidgetMoved(Uml::IDType)));
connect(m_pOw[Uml::B], TQ_SIGNAL(sigWidgetMoved(Uml::IDType)), this, TQ_SLOT(slotWidgetMoved(Uml::IDType)));
connect(this, TQ_SIGNAL(sigMessageMoved()), m_pOw[Uml::A], TQ_SLOT(slotMessageMoved()) );
connect(this, TQ_SIGNAL(sigMessageMoved()), m_pOw[Uml::B], TQ_SLOT(slotMessageMoved()) );
m_pOw[Uml::A] -> messageAdded(this);
m_pOw[Uml::B] -> messageAdded(this);
calculateDimensions();
emit sigMessageMoved();
return true;
}
void MessageWidget::setMessageText(FloatingTextWidget *ft) {
if (ft == NULL)
return;
TQString displayText = m_SequenceNumber + ": " + getOperationText(m_pView);
ft->setText(displayText);
setTextPosition();
}
void MessageWidget::setText(FloatingTextWidget *ft, const TQString &newText) {
ft->setText(newText);
UMLApp::app()->getDocument()->setModified(true);
}
void MessageWidget::setSeqNumAndOp(const TQString &seqNum, const TQString &op) {
setSequenceNumber( seqNum );
m_CustomOp = op; ///FIXME m_pOperation
}
void MessageWidget::setSequenceNumber( const TQString &sequenceNumber ) {
m_SequenceNumber = sequenceNumber;
}
TQString MessageWidget::getSequenceNumber() const {
return m_SequenceNumber;
}
void MessageWidget::lwSetFont (TQFont font) {
UMLWidget::setFont( font );
}
UMLClassifier *MessageWidget::getOperationOwner() {
UMLObject *pObject = m_pOw[Uml::B]->getUMLObject();
if (pObject == NULL)
return NULL;
UMLClassifier *c = dynamic_cast<UMLClassifier*>(pObject);
return c;
}
UMLOperation *MessageWidget::getOperation() {
return static_cast<UMLOperation*>(m_pObject);
}
void MessageWidget::setOperation(UMLOperation *op) {
if (m_pObject && m_pFText)
disconnect(m_pObject, TQ_SIGNAL(modified()), m_pFText, TQ_SLOT(setMessageText()));
m_pObject = op;
if (m_pObject && m_pFText)
connect(m_pObject, TQ_SIGNAL(modified()), m_pFText, TQ_SLOT(setMessageText()));
}
TQString MessageWidget::getCustomOpText() {
return m_CustomOp;
}
void MessageWidget::setCustomOpText(const TQString &opText) {
m_CustomOp = opText;
m_pFText->setMessageText();
}
UMLClassifier * MessageWidget::getSeqNumAndOp(TQString& seqNum, TQString& op) {
seqNum = m_SequenceNumber;
UMLOperation *pOperation = getOperation();
if (pOperation != NULL) {
op = pOperation->toString(Uml::st_SigNoVis);
} else {
op = m_CustomOp;
}
UMLObject *o = m_pOw[Uml::B]->getUMLObject();
UMLClassifier *c = dynamic_cast<UMLClassifier*>(o);
return c;
}
void MessageWidget::calculateDimensions() {
if (m_sequenceMessageType == Uml::sequence_message_synchronous) {
calculateDimensionsSynchronous();
} else if (m_sequenceMessageType == Uml::sequence_message_asynchronous) {
calculateDimensionsAsynchronous();
} else if (m_sequenceMessageType == Uml::sequence_message_creation) {
calculateDimensionsCreation();
} else {
kWarning() << "Unknown message type" << endl;
}
if (! UMLApp::app()->getDocument()->loading()) {
adjustAssocs( getX(), getY() ); // adjust assoc lines
}
}
void MessageWidget::calculateDimensionsSynchronous() {
int x = 0;
int x1 = m_pOw[Uml::A]->getX();
int x2 = m_pOw[Uml::B]->getX();
int w1 = m_pOw[Uml::A]->getWidth() / 2;
int w2 = m_pOw[Uml::B]->getWidth() / 2;
x1 += w1;
x2 += w2;
int widgetWidth = 0;
int widgetHeight = 0;
if( m_pOw[Uml::A] == m_pOw[Uml::B] ) {
widgetWidth = 50;
x = x1 - 2;
} else if( x1 < x2 ) {
x = x1;
widgetWidth = x2 - x1 + 8;
} else {
x = x2 - 8;
widgetWidth = x1 - x2 + 8;
}
if ( height() < 20 ) {
widgetHeight = 20;
} else {
widgetHeight = height();
}
m_nPosX = x;
setSize(widgetWidth, widgetHeight);
}
void MessageWidget::calculateDimensionsAsynchronous() {
int x = 0;
int x1 = m_pOw[Uml::A]->getX();
int x2 = m_pOw[Uml::B]->getX();
int w1 = m_pOw[Uml::A]->getWidth() / 2;
int w2 = m_pOw[Uml::B]->getWidth() / 2;
x1 += w1;
x2 += w2;
int widgetWidth = 0;
int widgetHeight = 8;
if( m_pOw[Uml::A] == m_pOw[Uml::B] ) {
widgetWidth = 50;
x = x1;
if( height() < 20 ) {
widgetHeight = 20;
} else {
widgetHeight = height();
}
} else if( x1 < x2 ) {
x = x1;
widgetWidth = x2 - x1;
} else {
x = x2;
widgetWidth = x1 - x2;
}
x += 1;
widgetWidth -= 2;
m_nPosX = x;
setSize(widgetWidth, widgetHeight);
}
void MessageWidget::calculateDimensionsCreation() {
int x = 0;
int x1 = m_pOw[Uml::A]->getX();
int x2 = m_pOw[Uml::B]->getX();
int w1 = m_pOw[Uml::A]->getWidth() / 2;
int w2 = m_pOw[Uml::B]->getWidth();
x1 += w1;
if (x1 > x2)
x2 += w2;
int widgetWidth = 0;
int widgetHeight = 8;
if ( x1 < x2 ) {
x = x1;
widgetWidth = x2 - x1;
} else {
x = x2;
widgetWidth = x1 - x2;
}
x += 1;
widgetWidth -= 2;
m_nPosX = x;
m_nY = m_pOw[Uml::B]->getY() + m_pOw[Uml::B]->getHeight() / 2;
setSize(widgetWidth, widgetHeight);
}
void MessageWidget::cleanup() {
if (m_pOw[Uml::A]) {
disconnect(this, TQ_SIGNAL(sigMessageMoved()), m_pOw[Uml::A], TQ_SLOT(slotMessageMoved()) );
m_pOw[Uml::A]->messageRemoved(this);
}
if (m_pOw[Uml::B]) {
disconnect(this, TQ_SIGNAL(sigMessageMoved()), m_pOw[Uml::B], TQ_SLOT(slotMessageMoved()) );
m_pOw[Uml::B]->messageRemoved(this);
}
UMLWidget::cleanup();
if (m_pFText) {
m_pView->removeWidget(m_pFText);
m_pFText = NULL;
}
}
void MessageWidget::setSelected(bool _select) {
UMLWidget::setSelected( _select );
if( !m_pFText || m_pFText->getDisplayText().isEmpty())
return;
if( m_bSelected && m_pFText -> getSelected() )
return;
if( !m_bSelected && !m_pFText -> getSelected() )
return;
m_pView -> setSelected( m_pFText, 0 );
m_pFText -> setSelected( m_bSelected );
}
int MessageWidget::getMinY() {
if (!m_pOw[Uml::A] || !m_pOw[Uml::B]) {
return 0;
}
if (m_sequenceMessageType == Uml::sequence_message_creation) {
return m_pOw[Uml::A]->getY() + m_pOw[Uml::A]->getHeight();
}
int heightA = m_pOw[Uml::A]->getY() + m_pOw[Uml::A]->getHeight();
int heightB = m_pOw[Uml::B]->getY() + m_pOw[Uml::B]->getHeight();
int height = heightA;
if( heightA < heightB ) {
height = heightB;
}
return height;
}
int MessageWidget::getMaxY() {
if( !m_pOw[Uml::A] || !m_pOw[Uml::B] ) {
return 0;
}
int heightA = (int)((ObjectWidget*)m_pOw[Uml::A])->getEndLineY();
int heightB = (int)((ObjectWidget*)m_pOw[Uml::B])->getEndLineY();
int height = heightA;
if( heightA > heightB ) {
height = heightB;
}
return (height - this->height());
}
void MessageWidget::setWidget(ObjectWidget * ow, Uml::Role_Type role) {
m_pOw[role] = ow;
updateResizability();
}
ObjectWidget* MessageWidget::getWidget(Uml::Role_Type role) {
return m_pOw[role];
}
void MessageWidget::saveToXMI( TQDomDocument & qDoc, TQDomElement & qElement ) {
TQDomElement messageElement = qDoc.createElement( "messagewidget" );
UMLWidget::saveToXMI( qDoc, messageElement );
messageElement.setAttribute( "widgetaid", ID2STR(m_pOw[Uml::A]->getLocalID()) );
messageElement.setAttribute( "widgetbid", ID2STR(m_pOw[Uml::B]->getLocalID()) );
UMLOperation *pOperation = getOperation();
if (pOperation)
messageElement.setAttribute( "operation", ID2STR(pOperation->getID()) );
else
messageElement.setAttribute( "operation", m_CustomOp );
messageElement.setAttribute( "seqnum", m_SequenceNumber );
messageElement.setAttribute( "sequencemessagetype", m_sequenceMessageType );
// save the corresponding message text
if (m_pFText && !m_pFText->getText().isEmpty()) {
messageElement.setAttribute( "textid", ID2STR(m_pFText->getID()) );
m_pFText -> saveToXMI( qDoc, messageElement );
}
qElement.appendChild( messageElement );
}
bool MessageWidget::loadFromXMI(TQDomElement& qElement) {
if ( !UMLWidget::loadFromXMI(qElement) ) {
return false;
}
TQString textid = qElement.attribute( "textid", "-1" );
TQString widgetaid = qElement.attribute( "widgetaid", "-1" );
TQString widgetbid = qElement.attribute( "widgetbid", "-1" );
m_CustomOp = qElement.attribute( "operation", "" );
m_SequenceNumber = qElement.attribute( "seqnum", "" );
TQString sequenceMessageType = qElement.attribute( "sequencemessagetype", "1001" );
m_sequenceMessageType = (Uml::Sequence_Message_Type)sequenceMessageType.toInt();
m_widgetAId = STR2ID(widgetaid);
m_widgetBId = STR2ID(widgetbid);
m_textId = STR2ID(textid);
Uml::Text_Role tr = Uml::tr_Seq_Message;
if (m_widgetAId == m_widgetBId)
tr = Uml::tr_Seq_Message_Self;
//now load child elements
TQDomNode node = qElement.firstChild();
TQDomElement element = node.toElement();
if ( !element.isNull() ) {
TQString tag = element.tagName();
if (tag == "floatingtext") {
m_pFText = new FloatingTextWidget( m_pView, tr, getOperationText(m_pView), m_textId );
if( ! m_pFText->loadFromXMI(element) ) {
// Most likely cause: The FloatingTextWidget is empty.
delete m_pFText;
m_pFText = NULL;
}
} else {
kError() << "MessageWidget::loadFromXMI: unknown tag "
<< tag << endl;
}
}
return true;
}
#include "messagewidget.moc"