umbrello API Documentation

floatingtextwidget.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 // own header
00013 #include "floatingtextwidget.h"
00014 
00015 // system includes
00016 #include <qregexp.h>
00017 #include <qpainter.h>
00018 #include <qevent.h>
00019 #include <qvalidator.h>
00020 #include <klocale.h>
00021 #include <kdebug.h>
00022 #include <kinputdialog.h>
00023 
00024 // local includes
00025 #include "floatingtextwidgetcontroller.h"
00026 #include "association.h"
00027 #include "umlview.h"
00028 #include "umldoc.h"
00029 #include "uml.h"
00030 #include "classifier.h"
00031 #include "listpopupmenu.h"
00032 #include "operation.h"
00033 #include "model_utils.h"
00034 #include "object_factory.h"
00035 #include "messagewidget.h"
00036 #include "dialogs/assocpropdlg.h"
00037 #include "dialogs/selectopdlg.h"
00038 
00039 
00040 FloatingTextWidget::FloatingTextWidget(UMLView * view, Uml::Text_Role role,
00041                                        const QString& text, Uml::IDType id)
00042   : UMLWidget(view, id, new FloatingTextWidgetController(this))
00043 {
00044     init();
00045     m_Text = text;
00046     m_Role = role;
00047     if ( ! UMLApp::app()->getDocument()->loading() ) {
00048         updateComponentSize();
00049         setZ( 10 );//make sure always on top.
00050         update();
00051     }
00052 }
00053 
00054 void FloatingTextWidget::init() {
00055     // initialize loaded/saved (i.e. persistent) data
00056     m_PreText = "";
00057     m_Text = "";
00058     m_PostText = "";
00059     m_Role = Uml::tr_Floating;
00060     m_Type = Uml::wt_Text;
00061     // initialize non-saved (i.e. volatile) data
00062     m_pLink = NULL;
00063     UMLWidget::m_bResizable = false;
00064 }
00065 
00066 FloatingTextWidget::~FloatingTextWidget() {
00067 }
00068 
00069 void FloatingTextWidget::draw(QPainter & p, int offsetX, int offsetY) {
00070     int w = width();
00071     int h = height();
00072     p.setFont( UMLWidget::getFont() );
00073     QColor textColor(50, 50, 50);
00074     p.setPen(textColor);
00075     p.drawText( offsetX , offsetY,w,h, Qt::AlignCenter, getDisplayText() );
00076     if(m_bSelected)
00077         drawSelected(&p, offsetX, offsetY);
00078 }
00079 
00080 void FloatingTextWidget::resizeEvent(QResizeEvent * /*re*/) {}
00081 
00082 QSize FloatingTextWidget::calculateSize() {
00083     const QFontMetrics &fm = getFontMetrics(FT_NORMAL);
00084     int h = fm.lineSpacing();
00085     int w = fm.width( getDisplayText() );
00086     return QSize(w + 8, h + 4);  // give a small margin
00087 }
00088 
00089 void FloatingTextWidget::slotMenuSelection(int sel) {
00090     switch(sel) {
00091     case ListPopupMenu::mt_Properties:
00092         showProperties();
00093         break;
00094 
00095     case ListPopupMenu::mt_Delete:
00096         m_pView -> removeWidget(this);
00097         break;
00098 
00099     case ListPopupMenu::mt_Operation:
00100         {
00101             kDebug() << "FloatingTextWidget::slotMenuSelection(mt_Operation) is called."
00102             << endl;
00103             if (m_pLink == NULL) {
00104                 kDebug() << "FloatingTextWidget::slotMenuSelection(mt_Operation): "
00105                 << "m_pLink is NULL" << endl;
00106                 return;
00107             }
00108             UMLClassifier* c = m_pLink->getOperationOwner();
00109             if (c == NULL) {
00110                 bool ok = false;
00111                 QString opText = KInputDialog::getText(i18n("Name"),
00112                                                        i18n("Enter operation name:"),
00113                                                        getText(), &ok, m_pView);
00114                 if (ok)
00115                     m_pLink->setCustomOpText(opText);
00116                 return;
00117             }
00118             UMLClassifierListItem* umlObj = Object_Factory::createChildObject(c, Uml::ot_Operation);
00119             if (umlObj) {
00120                 UMLOperation* newOperation = static_cast<UMLOperation*>( umlObj );
00121                 m_pLink->setOperation(newOperation);
00122             }
00123         }
00124         break;
00125 
00126     case ListPopupMenu::mt_Select_Operation:
00127         showOpDlg();
00128         break;
00129 
00130     case ListPopupMenu::mt_Rename:
00131         handleRename();
00132         break;
00133 
00134     case ListPopupMenu::mt_Change_Font:
00135         {
00136             QFont font = getFont();
00137             if( KFontDialog::getFont( font, false, m_pView ) ) {
00138                 if( m_Role == Uml::tr_Floating || m_Role == Uml::tr_Seq_Message ) {
00139                     setFont( font );
00140                 } else if (m_pLink) {
00141                     m_pLink->lwSetFont(font);
00142                 }
00143             }
00144         }
00145         break;
00146 
00147     case ListPopupMenu::mt_Reset_Label_Positions:
00148         if (m_pLink)
00149             m_pLink->resetTextPositions();
00150         break;
00151 
00152     default:
00153         UMLWidget::slotMenuSelection(sel);
00154         break;
00155     }//end switch
00156 }
00157 
00158 void FloatingTextWidget::handleRename() {
00159     QRegExpValidator v(QRegExp(".*"), 0);
00160     QString t;
00161     if( m_Role == Uml::tr_RoleAName || m_Role == Uml::tr_RoleBName ) {
00162         t = i18n("Enter role name:");
00163     } else if (m_Role == Uml::tr_MultiA || m_Role == Uml::tr_MultiB) {
00164         t = i18n("Enter multiplicity:");
00165         /*
00166         // NO! shouldn't be allowed
00167         } else if( m_Role == Uml::tr_ChangeA || m_Role == Uml::tr_ChangeB ) {
00168         t = i18n("Enter changeability");
00169         */
00170     } else if (m_Role == Uml::tr_Name) {
00171         t = i18n("Enter association name:");
00172     } else if (m_Role == Uml::tr_Floating) {
00173         t = i18n("Enter new text:");
00174     } else {
00175         t = i18n("ERROR");
00176     }
00177     bool ok = false;
00178     QString newText = KInputDialog::getText(i18n("Rename"), t, getText(), &ok,
00179                                             m_pView, NULL, &v);
00180     if (!ok || newText == getText())
00181         return;
00182     if (m_pLink && !isTextValid(newText)) {
00183         AssociationWidget *assoc = dynamic_cast<AssociationWidget*>(m_pLink);
00184         if (assoc) {
00185             switch (m_Role) {
00186               case Uml::tr_MultiA:
00187                 assoc->setMulti(QString::null, Uml::A);
00188                 break;
00189               case Uml::tr_MultiB:
00190                 assoc->setMulti(QString::null, Uml::B);
00191                 break;
00192               case Uml::tr_RoleAName:
00193                 assoc->setRoleName(QString::null, Uml::A);
00194                 break;
00195               case Uml::tr_RoleBName:
00196                 assoc->setRoleName(QString::null, Uml::B);
00197                 break;
00198               case Uml::tr_ChangeA:
00199                 assoc->setChangeability(Uml::chg_Changeable, Uml::A);
00200                 break;
00201               case Uml::tr_ChangeB:
00202                 assoc->setChangeability(Uml::chg_Changeable, Uml::B);
00203                 break;
00204               default:
00205                 assoc->setName(QString::null);
00206                 break;
00207             }
00208         } else {
00209             MessageWidget *msg = dynamic_cast<MessageWidget*>(m_pLink);
00210             if (msg) {
00211                 msg->setName(QString::null);
00212                 m_pView->removeWidget(this);
00213             }
00214         }
00215         return;
00216     }
00217     if (m_pLink && m_Role != Uml::tr_Seq_Message && m_Role != Uml::tr_Seq_Message_Self) {
00218         m_pLink->setText(this, newText);
00219     } else {
00220         setText( newText );
00221         UMLApp::app()->getDocument()->setModified(true);
00222     }
00223     setVisible( true );
00224     updateComponentSize();
00225     update();
00226 }
00227 
00228 void FloatingTextWidget::setText(const QString &t) {
00229     if (m_Role == Uml::tr_Seq_Message || m_Role == Uml::tr_Seq_Message_Self) {
00230         QString seqNum, op;
00231         m_pLink->getSeqNumAndOp(seqNum, op);
00232         if (seqNum.length() > 0 || op.length() > 0) {
00233             if (! m_pView->getShowOpSig())
00234                 op.replace( QRegExp("\\(.*\\)"), "()" );
00235             m_Text = seqNum.append(": ").append( op );
00236         } else
00237             m_Text = t;
00238     } else
00239         m_Text = t;
00240     updateComponentSize();
00241     update();
00242 }
00243 
00244 void FloatingTextWidget::setPreText (const QString &t)
00245 {
00246     m_PreText = t;
00247     updateComponentSize();
00248     update();
00249 }
00250 
00251 void FloatingTextWidget::setPostText(const QString &t) {
00252     m_PostText = t;
00253     updateComponentSize();
00254     update();
00255 }
00256 
00257 void FloatingTextWidget::changeTextDlg() {
00258     bool ok = false;
00259     QString newText = KInputDialog::getText(i18n("Change Text"), i18n("Enter new text:"), getText(), &ok, m_pView);
00260 
00261     if(ok && newText != getText() && isTextValid(newText)) {
00262         setText( newText );
00263         setVisible( ( getText().length() > 0 ) );
00264         updateComponentSize();
00265         update();
00266     }
00267     if(!isTextValid(newText))
00268         hide();
00269 }
00270 
00271 void FloatingTextWidget::showOpDlg() {
00272     if (m_pLink == NULL) {
00273         kError() << "FloatingTextWidget::showOpDlg: m_pLink is NULL" << endl;
00274         return;
00275     }
00276     QString seqNum, opText;
00277     UMLClassifier* c = m_pLink->getSeqNumAndOp(seqNum, opText);
00278     if (c == NULL) {
00279         kError() << "FloatingTextWidget::showOpDlg: "
00280         << "m_pLink->getSeqNumAndOp() returns a NULL classifier"
00281         << endl;
00282         return;
00283     }
00284 
00285     SelectOpDlg selectDlg(m_pView, c);
00286     selectDlg.setSeqNumber( seqNum );
00287     if (m_pLink->getOperation() == NULL) {
00288         selectDlg.setCustomOp( opText );
00289     } else {
00290         selectDlg.setClassOp( opText );
00291     }
00292     int result = selectDlg.exec();
00293     if(!result) {
00294         return;
00295     }
00296     seqNum = selectDlg.getSeqNumber();
00297     opText = selectDlg.getOpText();
00298     if (selectDlg.isClassOp()) {
00299         Model_Utils::OpDescriptor od;
00300         Model_Utils::Parse_Status st = Model_Utils::parseOperation(opText, od, c);
00301         if (st == Model_Utils::PS_OK) {
00302             UMLClassifierList selfAndAncestors = c->findSuperClassConcepts();
00303             selfAndAncestors.prepend(c);
00304             UMLOperation *op = NULL;
00305             for (UMLClassifier *cl = selfAndAncestors.first(); cl; cl = selfAndAncestors.next()) {
00306                 op = cl->findOperation(od.m_name, od.m_args);
00307                 if (op != NULL)
00308                     break;
00309             }
00310             if (op == NULL) {
00311                 // The op does not yet exist. Create a new one.
00312                 UMLObject *o = c->createOperation(od.m_name, NULL, &od.m_args);
00313                 op = static_cast<UMLOperation*>(o);
00314             }
00315             if (od.m_pReturnType)
00316                 op->setType(od.m_pReturnType);
00317             m_pLink->setOperation(op);
00318             opText = QString::null;
00319         } else {
00320             m_pLink->setOperation(NULL);
00321         }
00322     } else {
00323         m_pLink->setOperation(NULL);
00324     }
00325     m_pLink->setSeqNumAndOp(seqNum, opText);
00326     setMessageText();
00327 }
00328 
00329 QString FloatingTextWidget::getPreText() const {
00330     return m_PreText;
00331 }
00332 
00333 QString FloatingTextWidget::getPostText() const {
00334     return m_PostText;
00335 }
00336 
00337 QString FloatingTextWidget::getText() const {
00338     //test to make sure not just the ":" between the seq number
00339     //and the actual message widget
00340     // hmm. this section looks like it could have been avoided by using pre-, post- text
00341     // instead of storing in the main body of the text -b.t.
00342     if(m_Role == Uml::tr_Seq_Message || m_Role == Uml::tr_Seq_Message_Self ||
00343             m_Role == Uml::tr_Coll_Message || m_Role == Uml::tr_Coll_Message_Self) {
00344         if( m_Text.length() <= 1 || m_Text == ": " )
00345             return "";
00346     }
00347     return m_Text;
00348 }
00349 
00350 QString FloatingTextWidget::getDisplayText() const
00351 {
00352     QString displayText = m_Text;
00353     displayText.prepend(m_PreText);
00354     displayText.append(m_PostText);
00355     return displayText;
00356 }
00357 
00358 bool FloatingTextWidget::activate( IDChangeLog* ChangeLog /*= 0 */) {
00359     if (! UMLWidget::activate(ChangeLog))
00360         return false;
00361     update();
00362     return true;
00363 }
00364 
00365 void FloatingTextWidget::setLink(LinkWidget * l) {
00366     m_pLink = l;
00367 }
00368 
00369 LinkWidget * FloatingTextWidget::getLink() {
00370     return m_pLink;
00371 }
00372 
00373 void FloatingTextWidget::setRole(Uml::Text_Role role) {
00374     m_Role = role;
00375 }
00376 
00377 Uml::Text_Role FloatingTextWidget::getRole() const {
00378     return m_Role;
00379 }
00380 
00381 bool FloatingTextWidget::isTextValid( const QString &text ) {
00382     int length = text.length();
00383     if(length < 1)
00384         return false;
00385     for(int i=0;i<length;i++)
00386         if(!text.at(i).isSpace())
00387             return true;
00388     return false;
00389 }
00390 
00391 void FloatingTextWidget::showProperties() {
00392     if (m_Role == Uml::tr_Coll_Message || m_Role == Uml::tr_Coll_Message_Self ||
00393             m_Role == Uml::tr_Seq_Message || m_Role == Uml::tr_Seq_Message_Self) {
00394         showOpDlg();
00395     } else if (m_Role == Uml::tr_Floating) {
00396         // double clicking on a text line opens the dialog to change the text
00397         handleRename();
00398     } else if (m_pLink) {
00399         m_pLink->showDialog();
00400     }
00401 }
00402 
00403 void FloatingTextWidget::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
00404     QDomElement textElement = qDoc.createElement( "floatingtext" );
00405     UMLWidget::saveToXMI( qDoc, textElement );
00406     textElement.setAttribute( "text", m_Text );
00407     textElement.setAttribute( "pretext", m_PreText );
00408     textElement.setAttribute( "posttext", m_PostText );
00409 
00410     /* No need to save these - the messagewidget already did it.
00411     m_Operation  = qElement.attribute( "operation", "" );
00412     m_SeqNum = qElement.attribute( "seqnum", "" );
00413      */
00414 
00415     textElement.setAttribute( "role", m_Role );
00416     qElement.appendChild( textElement );
00417 }
00418 
00419 bool FloatingTextWidget::loadFromXMI( QDomElement & qElement ) {
00420     if( !UMLWidget::loadFromXMI( qElement ) )
00421         return false;
00422 
00423     QString role = qElement.attribute( "role", "" );
00424     if( !role.isEmpty() )
00425         m_Role = (Uml::Text_Role)role.toInt();
00426 
00427     m_PreText = qElement.attribute( "pretext", "" );
00428     m_PostText = qElement.attribute( "posttext", "" );
00429     m_Text = qElement.attribute( "text", "" );
00430     // If all texts are empty then this is a useless widget.
00431     // In that case we return false.
00432     // CAVEAT: The caller should not interpret the false return value
00433     //  as an indication of failure since previous umbrello versions
00434     //  saved lots of these empty FloatingTexts.
00435     bool isDummy = (m_Text.isEmpty() && m_PreText.isEmpty() && m_PostText.isEmpty());
00436     return !isDummy;
00437 }
00438 
00439 void FloatingTextWidget::setMessageText() {
00440     if (m_pLink)
00441         m_pLink->setMessageText(this);
00442     setVisible(getText().length() > 0);
00443     updateComponentSize();
00444 }
00445 
00446 
00447 #include "floatingtextwidget.moc"
00448 
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:57 2007 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003