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.
793 lines
25 KiB
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"
|