umbrello API Documentation

messagewidget.cpp

00001 /***************************************************************************
00002  *                                                                         *
00003  *   This program is free software; you can redistribute it and/or modify  *
00004  *   it under the terms of the GNU General Public License as published by  *
00005  *   the Free Software Foundation; either version 2 of the License, or     *
00006  *   (at your option) any later version.                                   *
00007  *                                                                         *
00008  *   copyright (C) 2002-2007                                               *
00009  *   Umbrello UML Modeller Authors <uml-devel@uml.sf.net>                  *
00010  ***************************************************************************/
00011 
00012 // onw header
00013 #include "messagewidget.h"
00014 
00015 //qt includes
00016 #include <qpainter.h>
00017 //kde includes
00018 #include <kdebug.h>
00019 #include <kcursor.h>
00020 //app includes
00021 #include "messagewidgetcontroller.h"
00022 #include "floatingtextwidget.h"
00023 #include "objectwidget.h"
00024 #include "classifier.h"
00025 #include "operation.h"
00026 #include "umlview.h"
00027 #include "umldoc.h"
00028 #include "uml.h"
00029 #include "uniqueid.h"
00030 #include "listpopupmenu.h"
00031 
00032 MessageWidget::MessageWidget(UMLView * view, ObjectWidget* a, ObjectWidget* b,
00033                              int y, Uml::Sequence_Message_Type sequenceMessageType,
00034                              Uml::IDType id /* = Uml::id_None */)
00035         : UMLWidget(view, id, new MessageWidgetController(this)) {
00036     init();
00037     m_pOw[Uml::A] = a;
00038     m_pOw[Uml::B] = b;
00039     m_nY = y;
00040     m_sequenceMessageType = sequenceMessageType;
00041     if (m_sequenceMessageType == Uml::sequence_message_creation) {
00042         y -= m_pOw[Uml::B]->getHeight() / 2;
00043         m_pOw[Uml::B]->setY(y);
00044     }
00045     updateResizability();
00046     calculateWidget();
00047     y = y < getMinY() ? getMinY() : y;
00048     y = y > getMaxY() ? getMaxY() : y;
00049     m_nY = y;
00050 
00051     this->activate();
00052 }
00053 
00054 MessageWidget::MessageWidget(UMLView * view, Uml::Sequence_Message_Type seqMsgType, Uml::IDType id)
00055         : UMLWidget(view, id, new MessageWidgetController(this)) {
00056     init();
00057     m_sequenceMessageType = seqMsgType;
00058 }
00059 
00060 void MessageWidget::init() {
00061     UMLWidget::setBaseType(Uml::wt_Message);
00062     m_bIgnoreSnapToGrid = true;
00063     m_bIgnoreSnapComponentSizeToGrid = true;
00064     m_pOw[Uml::A] = m_pOw[Uml::B] = NULL;
00065     m_pFText = NULL;
00066     m_nY = 0;
00067     setVisible(true);
00068 }
00069 
00070 MessageWidget::~MessageWidget() {
00071 }
00072 
00073 void MessageWidget::updateResizability() {
00074     if (m_sequenceMessageType == Uml::sequence_message_synchronous ||
00075         m_pOw[Uml::A] == m_pOw[Uml::B])
00076         UMLWidget::m_bResizable = true;
00077     else
00078         UMLWidget::m_bResizable = false;
00079 }
00080 
00081 void MessageWidget::draw(QPainter& p, int offsetX, int offsetY) {
00082     if(!m_pOw[Uml::A] || !m_pOw[Uml::B]) {
00083         return;
00084     }
00085     UMLWidget::setPen(p);
00086     if (m_sequenceMessageType == Uml::sequence_message_synchronous) {
00087         drawSynchronous(p, offsetX, offsetY);
00088     } else if (m_sequenceMessageType == Uml::sequence_message_asynchronous) {
00089         drawAsynchronous(p, offsetX, offsetY);
00090     } else if (m_sequenceMessageType == Uml::sequence_message_creation) {
00091         drawCreation(p, offsetX, offsetY);
00092     } else {
00093         kWarning() << "Unknown message type" << endl;
00094     }
00095 }
00096 
00097 void MessageWidget::drawSolidArrowhead(QPainter& p, int x, int y, Qt::ArrowType direction) {
00098     int arrowheadExtentX = 4;
00099     if (direction == Qt::RightArrow) {
00100         arrowheadExtentX = -arrowheadExtentX;
00101     }
00102     QPointArray points;
00103     points.putPoints(0, 3, x, y, x + arrowheadExtentX, y - 3, x + arrowheadExtentX, y + 3);
00104     p.setBrush( QBrush(p.pen().color()) );
00105     p.drawPolygon(points);
00106 }
00107 
00108 void MessageWidget::drawArrow(QPainter& p, int x, int y, int w,
00109                               Qt::ArrowType direction, bool useDottedLine /* = false */) {
00110     int arrowheadStartX = x;
00111     int arrowheadExtentX = 4;
00112     if (direction == Qt::RightArrow) {
00113         arrowheadStartX += w;
00114         arrowheadExtentX = -arrowheadExtentX;
00115     }
00116     // draw upper half of arrowhead
00117     p.drawLine(arrowheadStartX, y, arrowheadStartX + arrowheadExtentX, y - 3);
00118     // draw lower half of arrowhead
00119     p.drawLine(arrowheadStartX, y, arrowheadStartX + arrowheadExtentX, y + 3);
00120     // draw arrow line
00121     if (useDottedLine) {
00122         QPen pen = p.pen();
00123         pen.setStyle(Qt::DotLine);
00124         p.setPen(pen);
00125     }
00126     p.drawLine(x, y, x + w, y);
00127 }
00128 
00129 void MessageWidget::drawSynchronous(QPainter& p, int offsetX, int offsetY) {
00130     int x1 = m_pOw[Uml::A]->getX();
00131     int x2 = m_pOw[Uml::B]->getX();
00132     int w = getWidth() - 1;
00133     int h = getHeight();
00134 
00135     bool messageOverlaps = m_pOw[Uml::A] -> messageOverlap( getY(), this );
00136 
00137     if(m_pOw[Uml::A] == m_pOw[Uml::B]) {
00138         p.fillRect( offsetX, offsetY, 17, h,  QBrush(Qt::white) );              //box
00139         p.drawRect(offsetX, offsetY, 17, h);                                    //box
00140         offsetX += 17;
00141         w -= 17;
00142         offsetY += 3;
00143         const int lowerLineY = offsetY + h - 6;
00144         // draw upper line segment (leaving the life line)
00145         p.drawLine(offsetX, offsetY, offsetX + w, offsetY);
00146         // draw line segment parallel to (and at the right of) the life line
00147         p.drawLine(offsetX + w, offsetY, offsetX + w, lowerLineY);
00148         // draw lower line segment (back to the life line)
00149         drawArrow(p, offsetX, lowerLineY, w, Qt::LeftArrow);
00150         offsetX -= 17;
00151         offsetY -= 3;
00152     } else if(x1 < x2) {
00153         if (messageOverlaps)  {
00154             offsetX += 8;
00155             w -= 8;
00156         }
00157         QPen pen = p.pen();
00158         int startX = offsetX + w - 16;
00159         p.fillRect(startX, offsetY, 17, h,  QBrush(Qt::white));         //box
00160         p.drawRect(startX, offsetY, 17, h);                             //box
00161         p.drawLine(offsetX, offsetY + 4, startX, offsetY + 4);          //arrow line
00162         drawSolidArrowhead(p, startX - 1, offsetY + 4, Qt::RightArrow);
00163         drawArrow(p, offsetX, offsetY + h - 3, w - 16, Qt::LeftArrow, true); // return arrow
00164         if (messageOverlaps)  {
00165             offsetX -= 8; //reset for drawSelected()
00166         }
00167     } else      {
00168         if (messageOverlaps)  {
00169             w -=8;
00170         }
00171         QPen pen = p.pen();
00172         p.fillRect( offsetX, offsetY, 17, h,  QBrush(Qt::white) );              //box
00173         p.drawRect(offsetX, offsetY, 17, h);                                    //box
00174         p.drawLine(offsetX + 18, offsetY + 4, offsetX + w, offsetY + 4);        //arrow line
00175         drawSolidArrowhead(p, offsetX + 17, offsetY + 4, Qt::LeftArrow);
00176         drawArrow(p, offsetX + 18, offsetY + h - 3, w - 18, Qt::RightArrow, true); // return arrow
00177     }
00178 
00179     if(m_bSelected) {
00180         drawSelected(&p, offsetX, offsetY);
00181     }
00182 }
00183 
00184 void MessageWidget::drawAsynchronous(QPainter& p, int offsetX, int offsetY) {
00185     int x1 = m_pOw[Uml::A]->getX();
00186     int x2 = m_pOw[Uml::B]->getX();
00187     int w = getWidth() - 1;
00188     int h = getHeight() - 1;
00189     bool messageOverlapsA = m_pOw[Uml::A] -> messageOverlap( getY(), this );
00190     //bool messageOverlapsB = m_pOw[Uml::B] -> messageOverlap( getY(), this );
00191 
00192     if(m_pOw[Uml::A] == m_pOw[Uml::B]) {
00193         if (messageOverlapsA)  {
00194             offsetX += 7;
00195             w -= 7;
00196         }
00197         const int lowerLineY = offsetY + h - 3;
00198         // draw upper line segment (leaving the life line)
00199         p.drawLine(offsetX, offsetY, offsetX + w, offsetY);
00200         // draw line segment parallel to (and at the right of) the life line
00201         p.drawLine(offsetX + w, offsetY, offsetX + w, lowerLineY);
00202         // draw lower line segment (back to the life line)
00203         drawArrow(p, offsetX, lowerLineY, w, Qt::LeftArrow);
00204         if (messageOverlapsA)  {
00205             offsetX -= 7; //reset for drawSelected()
00206         }
00207     } else if(x1 < x2) {
00208         if (messageOverlapsA)  {
00209             offsetX += 7;
00210             w -= 7;
00211         }
00212         drawArrow(p, offsetX, offsetY + 4, w, Qt::RightArrow);
00213         if (messageOverlapsA)  {
00214             offsetX -= 7;
00215         }
00216     } else      {
00217         if (messageOverlapsA)  {
00218             w -= 7;
00219         }
00220         drawArrow(p, offsetX, offsetY + 4, w, Qt::LeftArrow);
00221     }
00222 
00223     if (m_bSelected)
00224         drawSelected(&p, offsetX, offsetY);
00225 }
00226 
00227 void MessageWidget::drawCreation(QPainter& p, int offsetX, int offsetY) {
00228     int x1 = m_pOw[Uml::A]->getX();
00229     int x2 = m_pOw[Uml::B]->getX();
00230     int w = getWidth() - 1;
00231     //int h = getHeight() - 1;
00232     bool messageOverlapsA = m_pOw[Uml::A] -> messageOverlap( getY(), this );
00233     //bool messageOverlapsB = m_pOw[Uml::B] -> messageOverlap( getY(), this );
00234 
00235     const int lineY = offsetY + 4;
00236     if (x1 < x2) {
00237         if (messageOverlapsA)  {
00238             offsetX += 7;
00239             w -= 7;
00240         }
00241         drawArrow(p, offsetX, lineY, w, Qt::RightArrow);
00242         if (messageOverlapsA)  {
00243             offsetX -= 7;
00244         }
00245     } else      {
00246         if (messageOverlapsA)  {
00247             w -= 7;
00248         }
00249         drawArrow(p, offsetX, lineY, w, Qt::LeftArrow);
00250     }
00251 
00252     if (m_bSelected)
00253         drawSelected(&p, offsetX, offsetY);
00254 }
00255 
00256 int MessageWidget::onWidget(const QPoint & p) {
00257     if (m_sequenceMessageType != Uml::sequence_message_synchronous) {
00258         return UMLWidget::onWidget(p);
00259     }
00260     // Synchronous message:
00261     // Consists of top arrow (call) and bottom arrow (return.)
00262     if (p.x() < getX() || p.x() > getX() + getWidth())
00263         return 0;
00264     const int tolerance = 5;  // pixels
00265     const int pY = p.y();
00266     const int topArrowY = getY() + 3;
00267     const int bottomArrowY = getY() + getHeight() - 3;
00268     if (pY < topArrowY - tolerance || pY > bottomArrowY + tolerance)
00269         return 0;
00270     if (getHeight() <= 2 * tolerance)
00271         return 1;
00272     if (pY > topArrowY + tolerance && pY < bottomArrowY - tolerance)
00273         return 0;
00274     return 1;
00275 }
00276 
00277 void MessageWidget::setTextPosition() {
00278     if (m_pFText == NULL) {
00279         kDebug() << "MessageWidget::setTextPosition: m_pFText is NULL"
00280         << endl;
00281         return;
00282     }
00283     if (m_pFText->getDisplayText().isEmpty()) {
00284         return;
00285     }
00286     m_pFText->updateComponentSize();
00287     int ftX = constrainX(m_pFText->getX(), m_pFText->getWidth(), m_pFText->getRole());
00288     int ftY = getY() - m_pFText->getHeight();
00289     m_pFText->setX( ftX );
00290     m_pFText->setY( ftY );
00291 }
00292 
00293 int MessageWidget::constrainX(int textX, int textWidth, Uml::Text_Role tr) {
00294     int result = textX;
00295     const int minTextX = getX() + 5;
00296     if (textX < minTextX || tr == Uml::tr_Seq_Message_Self) {
00297         result = minTextX;
00298     } else {
00299         ObjectWidget *objectAtRight = NULL;
00300         if (m_pOw[Uml::B]->getX() > m_pOw[Uml::A]->getX())
00301             objectAtRight = m_pOw[Uml::B];
00302         else
00303             objectAtRight = m_pOw[Uml::A];
00304         const int objRight_seqLineX = objectAtRight->getX() + objectAtRight->getWidth() / 2;
00305         const int maxTextX = objRight_seqLineX - textWidth - 5;
00306         if (maxTextX <= minTextX)
00307             result = minTextX;
00308         else if (textX > maxTextX)
00309             result = maxTextX;
00310     }
00311     return result;
00312 }
00313 
00314 void MessageWidget::constrainTextPos(int &textX, int &textY, int textWidth, int textHeight,
00315                                      Uml::Text_Role tr) {
00316     textX = constrainX(textX, textWidth, tr);
00317     // Constrain Y.
00318     const int minTextY = getMinY();
00319     const int maxTextY = getMaxY() - textHeight - 5;
00320     if (textY < minTextY)
00321         textY = minTextY;
00322     else if (textY > maxTextY)
00323         textY = maxTextY;
00324 //     setY( textY + textHeight );   // NB: side effect
00325 }
00326 
00327 void MessageWidget::setLinkAndTextPos() {
00328     if (m_pFText == NULL)
00329         return;
00330     m_pFText->setLink(this);
00331     setTextPosition();
00332 }
00333 
00334 void MessageWidget::moveEvent(QMoveEvent* /*m*/) {
00335     //kDebug() << "MessageWidget::moveEvent: m_pFText is " << m_pFText << endl;
00336     if (!m_pFText) {
00337         return;
00338     }
00339     //TODO why this condition?
00340 /*    if (m_pView->getSelectCount() > 2) {
00341         return;
00342     }*/
00343 
00344     setTextPosition();
00345 
00346     emit sigMessageMoved();
00347 }
00348 
00349 void MessageWidget::resizeEvent(QResizeEvent* /*re*/) {
00350 }
00351 
00352 void MessageWidget::calculateWidget() {
00353     setMessageText(m_pFText);
00354     calculateDimensions();
00355 
00356     setVisible(true);
00357 
00358     setX(m_nPosX);
00359     setY(m_nY);
00360 }
00361 
00362 void MessageWidget::slotWidgetMoved(Uml::IDType id) {
00363     const Uml::IDType idA = m_pOw[Uml::A]->getLocalID();
00364     const Uml::IDType idB = m_pOw[Uml::B]->getLocalID();
00365     if (idA != id && idB != id) {
00366         kDebug() << "MessageWidget::slotWidgetMoved(" << ID2STR(id)
00367             << "): ignoring for idA=" << ID2STR(idA)
00368             << ", idB=" << ID2STR(idB) << endl;
00369         return;
00370     }
00371     m_nY = getY();
00372     if (m_nY < getMinY())
00373         m_nY = getMinY();
00374     if (m_nY > getMaxY())
00375         m_nY = getMaxY();
00376     calculateWidget();
00377     if( !m_pFText )
00378         return;
00379     if (m_pView->getSelectCount(true) > 1)
00380         return;
00381     setTextPosition();
00382 }
00383 
00384 bool MessageWidget::contains(ObjectWidget * w) {
00385     if(m_pOw[Uml::A] == w || m_pOw[Uml::B] == w)
00386         return true;
00387     else
00388         return false;
00389 }
00390 
00391 void MessageWidget::slotMenuSelection(int sel) {
00392     if(sel == ListPopupMenu::mt_Delete) {
00393         // This will clean up this widget and the text widget:
00394         m_pView -> removeWidget(this);
00395     } else {
00396         if (m_pFText == NULL) {
00397             Uml::Text_Role tr = Uml::tr_Seq_Message;
00398             if (m_pOw[Uml::A] == m_pOw[Uml::B])
00399                 tr = Uml::tr_Seq_Message_Self;
00400             m_pFText = new FloatingTextWidget( m_pView, tr );
00401             m_pFText->setFont(UMLWidget::getFont());
00402             setLinkAndTextPos();
00403             m_pView->getWidgetList().append(m_pFText);
00404         }
00405         m_pFText -> slotMenuSelection(sel);
00406     }
00407 }
00408 
00409 bool MessageWidget::activate(IDChangeLog * Log /*= 0*/) {
00410     m_pView->resetPastePoint();
00411     // UMLWidget::activate(Log);   CHECK: I don't think we need this ?
00412     if (m_pOw[Uml::A] == NULL) {
00413         UMLWidget *pWA = m_pView->findWidget(m_widgetAId);
00414         if (pWA == NULL) {
00415             kDebug() << "MessageWidget::activate: role A object "
00416                 << ID2STR(m_widgetAId) << " not found" << endl;
00417             return false;
00418         }
00419         m_pOw[Uml::A] = dynamic_cast<ObjectWidget*>(pWA);
00420         if (m_pOw[Uml::A] == NULL) {
00421             kDebug() << "MessageWidget::activate: role A widget "
00422                 << ID2STR(m_widgetAId) << " is not an ObjectWidget" << endl;
00423             return false;
00424         }
00425     }
00426     if (m_pOw[Uml::B] == NULL) {
00427         UMLWidget *pWB = m_pView->findWidget(m_widgetBId);
00428         if (pWB == NULL) {
00429             kDebug() << "MessageWidget::activate: role B object "
00430                 << ID2STR(m_widgetBId) << " not found" << endl;
00431             return false;
00432         }
00433         m_pOw[Uml::B] = dynamic_cast<ObjectWidget*>(pWB);
00434         if (m_pOw[Uml::B] == NULL) {
00435             kDebug() << "MessageWidget::activate: role B widget "
00436                 << ID2STR(m_widgetBId) << " is not an ObjectWidget" << endl;
00437             return false;
00438         }
00439     }
00440     updateResizability();
00441 
00442     UMLClassifier *c = dynamic_cast<UMLClassifier*>(m_pOw[Uml::B]->getUMLObject());
00443     UMLOperation *op = NULL;
00444     if (c && !m_CustomOp.isEmpty()) {
00445         Uml::IDType opId = STR2ID(m_CustomOp);
00446         op = dynamic_cast<UMLOperation*>( c->findChildObjectById(opId, true) );
00447         if (op) {
00448             // If the UMLOperation is set, m_CustomOp isn't used anyway.
00449             // Just setting it empty for the sake of sanity.
00450             m_CustomOp = QString::null;
00451         }
00452     }
00453 
00454     if( !m_pFText ) {
00455         Uml::Text_Role tr = Uml::tr_Seq_Message;
00456         if (m_pOw[Uml::A] == m_pOw[Uml::B])
00457             tr = Uml::tr_Seq_Message_Self;
00458         m_pFText = new FloatingTextWidget( m_pView, tr, "" );
00459         m_pFText->setFont(UMLWidget::getFont());
00460     }
00461     if (op)
00462         setOperation(op);  // This requires a valid m_pFText.
00463     setLinkAndTextPos();
00464     m_pFText -> setText("");
00465     m_pFText->setActivated();
00466     QString messageText = m_pFText->getText();
00467     m_pFText->setVisible( messageText.length() > 1 );
00468 
00469     connect(m_pOw[Uml::A], SIGNAL(sigWidgetMoved(Uml::IDType)), this, SLOT(slotWidgetMoved(Uml::IDType)));
00470     connect(m_pOw[Uml::B], SIGNAL(sigWidgetMoved(Uml::IDType)), this, SLOT(slotWidgetMoved(Uml::IDType)));
00471 
00472     connect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::A], SLOT(slotMessageMoved()) );
00473     connect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::B], SLOT(slotMessageMoved()) );
00474     m_pOw[Uml::A] -> messageAdded(this);
00475     m_pOw[Uml::B] -> messageAdded(this);
00476     calculateDimensions();
00477 
00478     emit sigMessageMoved();
00479     return true;
00480 }
00481 
00482 void MessageWidget::setMessageText(FloatingTextWidget *ft) {
00483     if (ft == NULL)
00484         return;
00485     QString displayText = m_SequenceNumber + ": " + getOperationText(m_pView);
00486     ft->setText(displayText);
00487     setTextPosition();
00488 }
00489 
00490 void MessageWidget::setText(FloatingTextWidget *ft, const QString &newText) {
00491     ft->setText(newText);
00492     UMLApp::app()->getDocument()->setModified(true);
00493 }
00494 
00495 void MessageWidget::setSeqNumAndOp(const QString &seqNum, const QString &op) {
00496     setSequenceNumber( seqNum );
00497     m_CustomOp = op;   
00498 }
00499 
00500 void MessageWidget::setSequenceNumber( const QString &sequenceNumber ) {
00501     m_SequenceNumber = sequenceNumber;
00502 }
00503 
00504 QString MessageWidget::getSequenceNumber() const {
00505     return m_SequenceNumber;
00506 }
00507 
00508 void MessageWidget::lwSetFont (QFont font) {
00509     UMLWidget::setFont( font );
00510 }
00511 
00512 UMLClassifier *MessageWidget::getOperationOwner() {
00513     UMLObject *pObject = m_pOw[Uml::B]->getUMLObject();
00514     if (pObject == NULL)
00515         return NULL;
00516     UMLClassifier *c = dynamic_cast<UMLClassifier*>(pObject);
00517     return c;
00518 }
00519 
00520 UMLOperation *MessageWidget::getOperation() {
00521     return static_cast<UMLOperation*>(m_pObject);
00522 }
00523 
00524 void MessageWidget::setOperation(UMLOperation *op) {
00525     if (m_pObject && m_pFText)
00526         disconnect(m_pObject, SIGNAL(modified()), m_pFText, SLOT(setMessageText()));
00527     m_pObject = op;
00528     if (m_pObject && m_pFText)
00529         connect(m_pObject, SIGNAL(modified()), m_pFText, SLOT(setMessageText()));
00530 }
00531 
00532 QString MessageWidget::getCustomOpText() {
00533     return m_CustomOp;
00534 }
00535 
00536 void MessageWidget::setCustomOpText(const QString &opText) {
00537     m_CustomOp = opText;
00538     m_pFText->setMessageText();
00539 }
00540 
00541 UMLClassifier * MessageWidget::getSeqNumAndOp(QString& seqNum, QString& op) {
00542     seqNum = m_SequenceNumber;
00543     UMLOperation *pOperation = getOperation();
00544     if (pOperation != NULL) {
00545         op = pOperation->toString(Uml::st_SigNoVis);
00546     } else {
00547         op = m_CustomOp;
00548     }
00549     UMLObject *o = m_pOw[Uml::B]->getUMLObject();
00550     UMLClassifier *c = dynamic_cast<UMLClassifier*>(o);
00551     return c;
00552 }
00553 
00554 void MessageWidget::calculateDimensions() {
00555     if (m_sequenceMessageType == Uml::sequence_message_synchronous) {
00556         calculateDimensionsSynchronous();
00557     } else if (m_sequenceMessageType == Uml::sequence_message_asynchronous) {
00558         calculateDimensionsAsynchronous();
00559     } else if (m_sequenceMessageType == Uml::sequence_message_creation) {
00560         calculateDimensionsCreation();
00561     } else {
00562         kWarning() << "Unknown message type" << endl;
00563     }
00564     if (! UMLApp::app()->getDocument()->loading()) {
00565         adjustAssocs( getX(), getY() );  // adjust assoc lines
00566     }
00567 }
00568 
00569 void MessageWidget::calculateDimensionsSynchronous() {
00570     int x = 0;
00571 
00572     int x1 = m_pOw[Uml::A]->getX();
00573     int x2 = m_pOw[Uml::B]->getX();
00574     int w1 = m_pOw[Uml::A]->getWidth() / 2;
00575     int w2 = m_pOw[Uml::B]->getWidth() / 2;
00576     x1 += w1;
00577     x2 += w2;
00578 
00579     int widgetWidth = 0;
00580     int widgetHeight = 0;
00581     if( m_pOw[Uml::A] == m_pOw[Uml::B] ) {
00582         widgetWidth = 50;
00583         x = x1 - 2;
00584     } else if( x1 < x2 ) {
00585         x = x1;
00586         widgetWidth = x2 - x1 + 8;
00587     } else {
00588         x = x2 - 8;
00589         widgetWidth = x1 - x2 + 8;
00590     }
00591 
00592     if ( height() < 20 ) {
00593         widgetHeight = 20;
00594     } else {
00595         widgetHeight = height();
00596     }
00597 
00598     m_nPosX = x;
00599     setSize(widgetWidth, widgetHeight);
00600 }
00601 
00602 void MessageWidget::calculateDimensionsAsynchronous() {
00603     int x = 0;
00604 
00605     int x1 = m_pOw[Uml::A]->getX();
00606     int x2 = m_pOw[Uml::B]->getX();
00607     int w1 = m_pOw[Uml::A]->getWidth() / 2;
00608     int w2 = m_pOw[Uml::B]->getWidth() / 2;
00609     x1 += w1;
00610     x2 += w2;
00611 
00612     int widgetWidth = 0;
00613     int widgetHeight = 8;
00614     if( m_pOw[Uml::A] == m_pOw[Uml::B] ) {
00615         widgetWidth = 50;
00616         x = x1;
00617         if( height() < 20 ) {
00618             widgetHeight = 20;
00619         } else {
00620             widgetHeight = height();
00621         }
00622     } else if( x1 < x2 ) {
00623         x = x1;
00624         widgetWidth = x2 - x1;
00625     } else {
00626         x = x2;
00627         widgetWidth = x1 - x2;
00628     }
00629     x += 1;
00630     widgetWidth -= 2;
00631     m_nPosX = x;
00632     setSize(widgetWidth, widgetHeight);
00633 }
00634 
00635 void MessageWidget::calculateDimensionsCreation() {
00636     int x = 0;
00637 
00638     int x1 = m_pOw[Uml::A]->getX();
00639     int x2 = m_pOw[Uml::B]->getX();
00640     int w1 = m_pOw[Uml::A]->getWidth() / 2;
00641     int w2 = m_pOw[Uml::B]->getWidth();
00642     x1 += w1;
00643     if (x1 > x2)
00644         x2 += w2;
00645 
00646     int widgetWidth = 0;
00647     int widgetHeight = 8;
00648     if ( x1 < x2 ) {
00649         x = x1;
00650         widgetWidth = x2 - x1;
00651     } else {
00652         x = x2;
00653         widgetWidth = x1 - x2;
00654     }
00655     x += 1;
00656     widgetWidth -= 2;
00657     m_nPosX = x;
00658     m_nY = m_pOw[Uml::B]->getY() + m_pOw[Uml::B]->getHeight() / 2;
00659     setSize(widgetWidth, widgetHeight);
00660 }
00661 
00662 void MessageWidget::cleanup() {
00663     if (m_pOw[Uml::A]) {
00664         disconnect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::A], SLOT(slotMessageMoved()) );
00665         m_pOw[Uml::A]->messageRemoved(this);
00666     }
00667     if (m_pOw[Uml::B]) {
00668         disconnect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::B], SLOT(slotMessageMoved()) );
00669         m_pOw[Uml::B]->messageRemoved(this);
00670     }
00671 
00672     UMLWidget::cleanup();
00673     if (m_pFText) {
00674         m_pView->removeWidget(m_pFText);
00675         m_pFText = NULL;
00676     }
00677 }
00678 
00679 void MessageWidget::setSelected(bool _select) {
00680     UMLWidget::setSelected( _select );
00681     if( !m_pFText || m_pFText->getDisplayText().isEmpty())
00682         return;
00683     if( m_bSelected && m_pFText -> getSelected() )
00684         return;
00685     if( !m_bSelected && !m_pFText -> getSelected() )
00686         return;
00687 
00688     m_pView -> setSelected( m_pFText, 0 );
00689     m_pFText -> setSelected( m_bSelected );
00690 }
00691 
00692 int MessageWidget::getMinY() {
00693     if (!m_pOw[Uml::A] || !m_pOw[Uml::B]) {
00694         return 0;
00695     }
00696     if (m_sequenceMessageType == Uml::sequence_message_creation) {
00697         return m_pOw[Uml::A]->getY() + m_pOw[Uml::A]->getHeight();
00698     }
00699     int heightA = m_pOw[Uml::A]->getY() + m_pOw[Uml::A]->getHeight();
00700     int heightB = m_pOw[Uml::B]->getY() + m_pOw[Uml::B]->getHeight();
00701     int height = heightA;
00702     if( heightA < heightB ) {
00703         height = heightB;
00704     }
00705     return height;
00706 }
00707 
00708 int MessageWidget::getMaxY() {
00709     if( !m_pOw[Uml::A] || !m_pOw[Uml::B] ) {
00710         return 0;
00711     }
00712     int heightA = (int)((ObjectWidget*)m_pOw[Uml::A])->getEndLineY();
00713     int heightB = (int)((ObjectWidget*)m_pOw[Uml::B])->getEndLineY();
00714     int height = heightA;
00715     if( heightA > heightB ) {
00716         height = heightB;
00717     }
00718     return (height - this->height());
00719 }
00720 
00721 void MessageWidget::setWidget(ObjectWidget * ow, Uml::Role_Type role) {
00722     m_pOw[role] = ow;
00723     updateResizability();
00724 }
00725 
00726 ObjectWidget* MessageWidget::getWidget(Uml::Role_Type role) {
00727     return m_pOw[role];
00728 }
00729 
00730 void MessageWidget::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
00731     QDomElement messageElement = qDoc.createElement( "messagewidget" );
00732     UMLWidget::saveToXMI( qDoc, messageElement );
00733     messageElement.setAttribute( "widgetaid", ID2STR(m_pOw[Uml::A]->getLocalID()) );
00734     messageElement.setAttribute( "widgetbid", ID2STR(m_pOw[Uml::B]->getLocalID()) );
00735     UMLOperation *pOperation = getOperation();
00736     if (pOperation)
00737         messageElement.setAttribute( "operation", ID2STR(pOperation->getID()) );
00738     else
00739         messageElement.setAttribute( "operation", m_CustomOp );
00740     messageElement.setAttribute( "seqnum", m_SequenceNumber );
00741     messageElement.setAttribute( "sequencemessagetype", m_sequenceMessageType );
00742 
00743     // save the corresponding message text
00744     if (m_pFText && !m_pFText->getText().isEmpty()) {
00745         messageElement.setAttribute( "textid", ID2STR(m_pFText->getID()) );
00746         m_pFText -> saveToXMI( qDoc, messageElement );
00747     }
00748 
00749     qElement.appendChild( messageElement );
00750 }
00751 
00752 bool MessageWidget::loadFromXMI(QDomElement& qElement) {
00753     if ( !UMLWidget::loadFromXMI(qElement) ) {
00754         return false;
00755     }
00756     QString textid = qElement.attribute( "textid", "-1" );
00757     QString widgetaid = qElement.attribute( "widgetaid", "-1" );
00758     QString widgetbid = qElement.attribute( "widgetbid", "-1" );
00759     m_CustomOp = qElement.attribute( "operation", "" );
00760     m_SequenceNumber = qElement.attribute( "seqnum", "" );
00761     QString sequenceMessageType = qElement.attribute( "sequencemessagetype", "1001" );
00762     m_sequenceMessageType = (Uml::Sequence_Message_Type)sequenceMessageType.toInt();
00763 
00764     m_widgetAId = STR2ID(widgetaid);
00765     m_widgetBId = STR2ID(widgetbid);
00766     m_textId = STR2ID(textid);
00767 
00768     Uml::Text_Role tr = Uml::tr_Seq_Message;
00769     if (m_widgetAId == m_widgetBId)
00770         tr = Uml::tr_Seq_Message_Self;
00771 
00772     //now load child elements
00773     QDomNode node = qElement.firstChild();
00774     QDomElement element = node.toElement();
00775     if ( !element.isNull() ) {
00776         QString tag = element.tagName();
00777         if (tag == "floatingtext") {
00778             m_pFText = new FloatingTextWidget( m_pView, tr, getOperationText(m_pView), m_textId );
00779             if( ! m_pFText->loadFromXMI(element) ) {
00780                 // Most likely cause: The FloatingTextWidget is empty.
00781                 delete m_pFText;
00782                 m_pFText = NULL;
00783             }
00784         } else {
00785             kError() << "MessageWidget::loadFromXMI: unknown tag "
00786             << tag << endl;
00787         }
00788     }
00789     return true;
00790 }
00791 
00792 #include "messagewidget.moc"
KDE Logo
This file is part of the documentation for umbrello Version 3.1.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Jun 26 08:07:58 2007 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003