umbrello API Documentation

operation.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 "operation.h"
00014 
00015 // qt/kde includes
00016 #include <qregexp.h>
00017 #include <kdebug.h>
00018 #include <klocale.h>
00019 
00020 // app includes
00021 #include "attribute.h"
00022 #include "classifier.h"
00023 #include "uml.h"
00024 #include "umldoc.h"
00025 #include "uniqueid.h"
00026 #include "dialogs/umloperationdialog.h"
00027 
00028 UMLOperation::UMLOperation(const UMLClassifier *parent, const QString& name,
00029                            Uml::IDType id, Uml::Visibility s, UMLObject *rt)
00030         : UMLClassifierListItem(parent, name, id)
00031 {
00032     if (rt)
00033         m_returnId = UniqueID::gen();
00034     else
00035         m_returnId = Uml::id_None;
00036     m_pSecondary = rt;
00037     m_Vis = s;
00038     m_BaseType = Uml::ot_Operation;
00039     m_bConst = false;
00040 }
00041 
00042 UMLOperation::UMLOperation(const UMLClassifier * parent)
00043         : UMLClassifierListItem (parent)
00044 {
00045     m_BaseType = Uml::ot_Operation;
00046     m_bConst = false;
00047 }
00048 
00049 UMLOperation::~UMLOperation() {
00050 }
00051 
00052 void UMLOperation::setType(UMLObject *type) {
00053     UMLClassifierListItem::setType(type);
00054     if (m_returnId == Uml::id_None)
00055         m_returnId = UniqueID::gen();
00056 }
00057 
00058 void UMLOperation::moveParmLeft(UMLAttribute * a) {
00059     if (a == NULL) {
00060         kDebug() << "UMLOperation::moveParmLeft called on NULL attribute"
00061         << endl;
00062         return;
00063     }
00064     kDebug() << "UMLOperation::moveParmLeft(" << a->getName() << ") called"
00065     << endl;
00066     disconnect(a,SIGNAL(modified()),this,SIGNAL(modified()));
00067     int idx;
00068     if ( (idx=m_List.find( a )) == -1 ) {
00069         kDebug() << "Error move parm left " << a->getName() << endl;
00070         return;
00071     }
00072     if ( idx == 0 )
00073         return;
00074     m_List.remove( a );
00075     m_List.insert( idx-1, a );
00076 }
00077 
00078 void UMLOperation::moveParmRight(UMLAttribute * a) {
00079     if (a == NULL) {
00080         kDebug() << "UMLOperation::moveParmRight called on NULL attribute"
00081         << endl;
00082         return;
00083     }
00084     kDebug() << "UMLOperation::moveParmRight(" << a->getName() << ") called"
00085     << endl;
00086     disconnect(a,SIGNAL(modified()),this,SIGNAL(modified()));
00087     int idx;
00088     if ( (idx=m_List.find( a )) == -1 ) {
00089         kDebug() << "Error move parm right " << a->getName() << endl;
00090         return;
00091     }
00092     int count = m_List.count();
00093     if ( idx == count-1 )
00094         return;
00095     m_List.remove( a );
00096     m_List.insert( idx+1, a );
00097 }
00098 
00099 void UMLOperation::removeParm(UMLAttribute * a, bool emitModifiedSignal /* =true */) {
00100     if (a == NULL) {
00101         kDebug() << "UMLOperation::removeParm called on NULL attribute"
00102         << endl;
00103         return;
00104     }
00105     kDebug() << "UMLOperation::removeParm(" << a->getName() << ") called"
00106     << endl;
00107     disconnect(a,SIGNAL(modified()),this,SIGNAL(modified()));
00108     if(!m_List.remove(a))
00109         kDebug() << "Error removing parm " << a->getName() << endl;
00110 
00111     if (emitModifiedSignal)
00112         emit modified();
00113 }
00114 
00115 UMLAttribute* UMLOperation::findParm(const QString &name) {
00116     UMLAttribute * obj=0;
00117     for (obj = m_List.first(); obj; obj = m_List.next()) {
00118         if (obj->getName() == name)
00119             return obj;
00120     }
00121     return 0;
00122 }
00123 
00124 QString UMLOperation::toString(Uml::Signature_Type sig) {
00125     QString s = "";
00126 
00127     if(sig == Uml::st_ShowSig || sig == Uml::st_NoSig)
00128           s = m_Vis.toString(true) + ' ';
00129 
00130     s += getName();
00131     Uml::Programming_Language pl = UMLApp::app()->getActiveLanguage();
00132     bool parameterlessOpNeedsParentheses = (pl != Uml::pl_Pascal && pl != Uml::pl_Ada);
00133 
00134     if (sig == Uml::st_NoSig || sig == Uml::st_NoSigNoVis) {
00135         if (parameterlessOpNeedsParentheses)
00136             s.append("()");
00137         return s;
00138     }
00139     int last = m_List.count();
00140     if (last) {
00141         s.append("(");
00142         int i = 0;
00143         for (UMLAttribute *param = m_List.first(); param; param = m_List.next()) {
00144             i++;
00145             s.append(param->toString(Uml::st_SigNoVis));
00146             if (i < last)
00147                 s.append(", ");
00148         }
00149         s.append(")");
00150     } else if (parameterlessOpNeedsParentheses) {
00151         s.append("()");
00152     }
00153     UMLClassifier *ownParent = static_cast<UMLClassifier*>(parent());
00154     QString returnType;
00155     UMLClassifier *retType = UMLClassifierListItem::getType();
00156     if (retType) {
00157         UMLPackage *retVisibility = retType->getUMLPackage();
00158         if (retVisibility != ownParent && retVisibility != ownParent->getUMLPackage())
00159             returnType = retType->getFullyQualifiedName();
00160         else
00161             returnType = retType->getName();
00162     }
00163     if (returnType.length() > 0 && returnType != "void") {
00164         s.append(" : ");
00165 
00166         if (returnType.startsWith("virtual ")) {
00167             s += returnType.mid(8);
00168         } else {
00169             s += returnType;
00170         }
00171     }
00172     return s;
00173 }
00174 
00175 void UMLOperation::addParm(UMLAttribute *parameter, int position) {
00176     if( position >= 0 && position <= (int)m_List.count() )
00177         m_List.insert(position,parameter);
00178     else
00179         m_List.append( parameter );
00180     UMLObject::emitModified();
00181     connect(parameter,SIGNAL(modified()),this,SIGNAL(modified()));
00182 }
00183 
00184 QString UMLOperation::getUniqueParameterName() {
00185     QString currentName = i18n("new_parameter");
00186     QString name = currentName;
00187     for (int number = 1; findParm(name); number++) {
00188         name = currentName + '_' + QString::number(number);
00189     }
00190     return name;
00191 }
00192 
00193 bool UMLOperation::operator==( UMLOperation & rhs ) {
00194     if( this == &rhs )
00195         return true;
00196 
00197     if( !UMLObject::operator==( rhs ) )
00198         return false;
00199 
00200     if( getTypeName() != rhs.getTypeName() )
00201         return false;
00202 
00203     if( m_List.count() != rhs.m_List.count() )
00204         return false;
00205 
00206     if(!(m_List == rhs.m_List))
00207         return false;
00208 
00209     return true;
00210 }
00211 
00212 void UMLOperation::copyInto(UMLOperation *rhs) const
00213 {
00214     UMLClassifierListItem::copyInto(rhs);
00215 
00216     m_List.copyInto(&(rhs->m_List));
00217 }
00218 
00219 UMLObject* UMLOperation::clone() const
00220 {
00221     //FIXME: The new operation should be slaved to the NEW parent not the old.
00222     UMLOperation *clone = new UMLOperation( static_cast<UMLClassifier*>(parent()) );
00223     copyInto(clone);
00224 
00225     return clone;
00226 }
00227 
00228 bool UMLOperation::resolveRef() {
00229     bool overallSuccess = UMLObject::resolveRef();
00230     // See remark on iteration style in UMLClassifier::resolveRef()
00231     for (UMLAttributeListIt ait(m_List); ait.current(); ++ait) {
00232         UMLAttribute *pAtt = ait.current();
00233         if (! pAtt->resolveRef())
00234             overallSuccess = false;
00235     }
00236     return overallSuccess;
00237 }
00238 
00239 bool UMLOperation::isConstructorOperation() {
00240     // if an operation has the stereotype constructor
00241     // return true
00242     QString strConstructor ("constructor");
00243     if (getStereotype() == strConstructor)
00244         return true;
00245 
00246     UMLClassifier * c = static_cast<UMLClassifier*>(this->parent());
00247     QString cName = c->getName();
00248     QString opName = getName();
00249     // It's a constructor operation if the operation name
00250     // matches that of the parent classifier.
00251     return (cName == opName);
00252 }
00253 
00254 bool UMLOperation::isDestructorOperation() {
00255     if (getStereotype() == "destructor")
00256         return true;
00257     UMLClassifier * c = static_cast<UMLClassifier*>(this->parent());
00258 
00259     QString cName = c->getName();
00260     QString opName = getName();
00261     // Special support for C++ syntax:
00262     // It's a destructor operation if the operation name begins
00263     // with "~" followed by the name of the parent classifier.
00264     if (! opName.startsWith("~"))
00265         return false;
00266     opName.remove( QRegExp("^~\\s*") );
00267     return (cName == opName);
00268 }
00269 
00270 bool UMLOperation::isLifeOperation() {
00271     return (isConstructorOperation() || isDestructorOperation());
00272 }
00273 
00274 void UMLOperation::setConst(bool b) {
00275     m_bConst = b;
00276 }
00277 
00278 bool UMLOperation::getConst() const {
00279     return m_bConst;
00280 }
00281 
00282 bool UMLOperation::showPropertiesDialog(QWidget* parent) {
00283     UMLOperationDialog dialog(parent, this);
00284     return dialog.exec();
00285 }
00286 
00287 void UMLOperation::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
00288     QDomElement operationElement = UMLObject::save("UML:Operation", qDoc);
00289     operationElement.setAttribute( "isQuery", m_bConst ? "true" : "false" );
00290     QDomElement featureElement = qDoc.createElement( "UML:BehavioralFeature.parameter" );
00291     if (m_pSecondary) {
00292         QDomElement retElement = qDoc.createElement("UML:Parameter");
00293         if (m_returnId == Uml::id_None) {
00294             kDebug() << "UMLOperation::saveToXMI(" << m_Name
00295                 << "): m_returnId is not set, setting it now." << endl;
00296             m_returnId = UniqueID::gen();
00297         }
00298         retElement.setAttribute( "xmi.id", ID2STR(m_returnId) );
00299         retElement.setAttribute( "type", ID2STR(m_pSecondary->getID()) );
00300         retElement.setAttribute( "kind", "return" );
00301         featureElement.appendChild( retElement );
00302     } else {
00303         kDebug() << "UMLOperation::saveToXMI: m_SecondaryId is "
00304         << m_SecondaryId << endl;
00305     }
00306     //save each attribute here, type different
00307     UMLAttribute* pAtt = 0;
00308     for( pAtt = m_List.first(); pAtt != 0; pAtt = m_List.next() ) {
00309         QDomElement attElement = pAtt->UMLObject::save("UML:Parameter", qDoc);
00310         UMLClassifier *attrType = pAtt->getType();
00311         if (attrType) {
00312             attElement.setAttribute( "type", ID2STR(attrType->getID()) );
00313         } else {
00314             attElement.setAttribute( "type", pAtt -> getTypeName() );
00315         }
00316         attElement.setAttribute( "value", pAtt -> getInitialValue() );
00317 
00318         Uml::Parameter_Direction kind = pAtt->getParmKind();
00319         if (kind == Uml::pd_Out)
00320             attElement.setAttribute("kind", "out");
00321         else if (kind == Uml::pd_InOut)
00322             attElement.setAttribute("kind", "inout");
00323         // The default for the parameter kind is "in".
00324 
00325         featureElement.appendChild( attElement );
00326     }
00327     if (featureElement.hasChildNodes())
00328         operationElement.appendChild( featureElement );
00329     qElement.appendChild( operationElement );
00330 }
00331 
00332 bool UMLOperation::load( QDomElement & element ) {
00333     m_SecondaryId = element.attribute( "type", "" );
00334     QString isQuery = element.attribute( "isQuery", "" );
00335     if (!isQuery.isEmpty()) {
00336         // We need this extra test for isEmpty() because load() might have been
00337         // called again by the processing for BehavioralFeature.parameter (see below)
00338         m_bConst = (isQuery == "true");
00339     }
00340     QDomNode node = element.firstChild();
00341     if (node.isComment())
00342         node = node.nextSibling();
00343     QDomElement attElement = node.toElement();
00344     while( !attElement.isNull() ) {
00345         QString tag = attElement.tagName();
00346         if (Uml::tagEq(tag, "BehavioralFeature.parameter")) {
00347             if (! load(attElement))
00348                 return false;
00349         } else if (Uml::tagEq(tag, "Parameter")) {
00350             QString kind = attElement.attribute("kind", "");
00351             if (kind.isEmpty()) {
00352                 // Perhaps the kind is stored in a child node:
00353                 for (QDomNode n = attElement.firstChild(); !n.isNull(); n = n.nextSibling()) {
00354                     if (n.isComment())
00355                         continue;
00356                     QDomElement tempElement = n.toElement();
00357                     QString tag = tempElement.tagName();
00358                     if (!Uml::tagEq(tag, "kind"))
00359                         continue;
00360                     kind = tempElement.attribute( "xmi.value", "" );
00361                     break;
00362                 }
00363                 if (kind.isEmpty()) {
00364                     // kDebug() << "UMLOperation::load(" << m_Name << "): "
00365                     //  << "cannot find kind, using default \"in\"." << endl;
00366                     kind = "in";
00367                 }
00368             }
00369             if (kind == "return") {
00370                 QString returnId = attElement.attribute("xmi.id", "");
00371                 if (!returnId.isEmpty())
00372                     m_returnId = STR2ID(returnId);
00373                 m_SecondaryId = attElement.attribute( "type", "" );
00374                 if (m_SecondaryId.isEmpty()) {
00375                     // Perhaps the type is stored in a child node:
00376                     QDomNode node = attElement.firstChild();
00377                     while (!node.isNull()) {
00378                         if (node.isComment()) {
00379                             node = node.nextSibling();
00380                             continue;
00381                         }
00382                         QDomElement tempElement = node.toElement();
00383                         QString tag = tempElement.tagName();
00384                         if (!Uml::tagEq(tag, "type")) {
00385                             node = node.nextSibling();
00386                             continue;
00387                         }
00388                         m_SecondaryId = tempElement.attribute( "xmi.id", "" );
00389                         if (m_SecondaryId.isEmpty())
00390                             m_SecondaryId = tempElement.attribute( "xmi.idref", "" );
00391                         if (m_SecondaryId.isEmpty()) {
00392                             QDomNode inner = node.firstChild();
00393                             QDomElement tmpElem = inner.toElement();
00394                             m_SecondaryId = tmpElem.attribute( "xmi.id", "" );
00395                             if (m_SecondaryId.isEmpty())
00396                                 m_SecondaryId = tmpElem.attribute( "xmi.idref", "" );
00397                         }
00398                         break;
00399                     }
00400                     if (m_SecondaryId.isEmpty()) {
00401                         kError() << "UMLOperation::load(" << m_Name << "): "
00402                         << "cannot find return type." << endl;
00403                     }
00404                 }
00405                 // Use deferred xmi.id resolution.
00406                 m_pSecondary = NULL;
00407             } else {
00408                 UMLAttribute * pAtt = new UMLAttribute( this );
00409                 if( !pAtt->loadFromXMI(attElement) ) {
00410                     delete pAtt;
00411                     return false;
00412                 }
00413                 if (kind == "out")
00414                     pAtt->setParmKind(Uml::pd_Out);
00415                 else if (kind == "inout")
00416                     pAtt->setParmKind(Uml::pd_InOut);
00417                 else
00418                     pAtt->setParmKind(Uml::pd_In);
00419                 m_List.append( pAtt );
00420             }
00421         }
00422         node = node.nextSibling();
00423         if (node.isComment())
00424             node = node.nextSibling();
00425         attElement = node.toElement();
00426     }//end while
00427     return true;
00428 }
00429 
00430 
00431 #include "operation.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