/*************************************************************************** * * * 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 * ***************************************************************************/ // onw header #include "messagewidget.h" //qt includes #include //kde includes #include #include //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(Qt::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(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(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(m_pOw[Uml::B]->getUMLObject()); UMLOperation *op = NULL; if (c && !m_CustomOp.isEmpty()) { Uml::IDType opId = STR2ID(m_CustomOp); op = dynamic_cast( 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], TQT_SIGNAL(sigWidgetMoved(Uml::IDType)), this, TQT_SLOT(slotWidgetMoved(Uml::IDType))); connect(m_pOw[Uml::B], TQT_SIGNAL(sigWidgetMoved(Uml::IDType)), this, TQT_SLOT(slotWidgetMoved(Uml::IDType))); connect(this, TQT_SIGNAL(sigMessageMoved()), m_pOw[Uml::A], TQT_SLOT(slotMessageMoved()) ); connect(this, TQT_SIGNAL(sigMessageMoved()), m_pOw[Uml::B], TQT_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(pObject); return c; } UMLOperation *MessageWidget::getOperation() { return static_cast(m_pObject); } void MessageWidget::setOperation(UMLOperation *op) { if (m_pObject && m_pFText) disconnect(m_pObject, TQT_SIGNAL(modified()), m_pFText, TQT_SLOT(setMessageText())); m_pObject = op; if (m_pObject && m_pFText) connect(m_pObject, TQT_SIGNAL(modified()), m_pFText, TQT_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(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, TQT_SIGNAL(sigMessageMoved()), m_pOw[Uml::A], TQT_SLOT(slotMessageMoved()) ); m_pOw[Uml::A]->messageRemoved(this); } if (m_pOw[Uml::B]) { disconnect(this, TQT_SIGNAL(sigMessageMoved()), m_pOw[Uml::B], TQT_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"