umbrello API Documentation

cppwriter.cpp

00001 /***************************************************************************
00002  *                        cppwriter.cpp  -  description                    *
00003  *  This is the "old" code generator that does not support code editing    *
00004  *  in the Modeller but uses significantly less file space because the     *
00005  *  source code is not replicated in the XMI file.                         *
00006  *                                                                         *
00007  *  copyright       : (C) 2003 Brian Thomas brian.thomas@gsfc.nasa.gov     *
00008  *  (C) 2004-2006  Umbrello UML Modeller Authors <uml-devel@uml.sf.net>    *
00009  *                                                                         *
00010  ***************************************************************************
00011  *                                                                         *
00012  *   This program is free software; you can redistribute it and/or modify  *
00013  *   it under the terms of the GNU General Public License as published by  *
00014  *   the Free Software Foundation; either version 2 of the License, or     *
00015  *   (at your option) any later version.                                   *
00016  *                                                                         *
00017  ***************************************************************************/
00018 
00019 // own header
00020 #include "cppwriter.h"
00021 // qt/kde includes
00022 #include <qfile.h>
00023 #include <qtextstream.h>
00024 #include <qregexp.h>
00025 #include <kdebug.h>
00026 // app includes
00027 #include "classifierinfo.h"
00028 #include "codegen_utils.h"
00029 #include "../uml.h"
00030 #include "../umldoc.h"
00031 #include "../classifier.h"
00032 #include "../operation.h"
00033 #include "../template.h"
00034 #include "../umltemplatelist.h"
00035 #include "../umlclassifierlistitemlist.h"
00036 #include "../classifierlistitem.h"
00037 #include "../model_utils.h"
00038 #include "../codegenerationpolicy.h"
00039 
00040 // 3-14-2003: this code developed from the javawriter with parts of the
00041 // original cppwriter by Luis De la Parra Blum
00042 
00043 CppWriter::CppWriter()
00044 {
00045     // Probably we could resolve this better through the use of templates,
00046     // but its a quick n dirty fix for the timebeing.. until codegeneration
00047     // template system is in place.
00048     // You can insert code here. 3 general variables exist: "%VARNAME%"
00049     // allows you to specify where the vector variable should be in your code,
00050     // and "%ITEMCLASS%", if needed, where the class of the item is declared.
00051     VECTOR_METHOD_APPEND = "%VARNAME%.push_back(add_object);"; // for std::vector
00052     VECTOR_METHOD_REMOVE = "int i, size = %VARNAME%.size();\nfor ( i = 0; i < size; i++) {\n\t%ITEMCLASS% item = %VARNAME%.at(i);\n\tif(item == remove_object) {\n\t\tvector<%ITEMCLASS%>::iterator it = %VARNAME%.begin() + i;\n\t\t%VARNAME%.erase(it);\n\t\treturn;\n\t}\n }"; // for std::vector
00053     VECTOR_METHOD_INIT = QString(); // nothing to be done
00054     /*
00055         VECTOR_METHOD_APPEND = "%VARNAME%.append(&add_object);"; // Qt lib implementation
00056         VECTOR_METHOD_REMOVE = "%VARNAME%.removeRef(&remove_object);"; // Qt lib implementation
00057         VECTOR_METHOD_INIT = "%VARNAME%.setAutoDelete(false);"; // Qt library
00058     */
00059 
00060     OBJECT_METHOD_INIT = "%VARNAME% = new %ITEMCLASS%( );"; // Qt library
00061 
00062     // boolean config params
00063     INLINE_ASSOCIATION_METHODS = false;
00064 
00065 }
00066 
00067 CppWriter::~CppWriter() { }
00068 
00069 Uml::Programming_Language CppWriter::getLanguage() {
00070     return Uml::pl_Cpp;
00071 }
00072 
00073 CPPCodeGenerationPolicy *CppWriter::policyExt() {
00074     return static_cast<CPPCodeGenerationPolicy*>(UMLApp::app()->getPolicyExt());
00075 }
00076 
00077 void CppWriter::writeClass(UMLClassifier *c)
00078 {
00079 
00080     if (!c) {
00081         kDebug() << "Cannot write class of NULL concept!\n";
00082         return;
00083     }
00084 
00085     QFile fileh, filecpp;
00086 
00087     // find an appropriate name for our file
00088     QString fileName = findFileName(c, ".h");
00089     if (fileName.isEmpty()) {
00090         emit codeGenerated(c, false);
00091         return;
00092     }
00093 
00094     // preparations
00095     m_classifierInfo = new ClassifierInfo(c, m_doc);
00096     m_classifierInfo->fileName = fileName;
00097     m_classifierInfo->className = cleanName(c->getName());
00098 
00099     if (c->getVisibility() != Uml::Visibility::Implementation) {
00100         if( !openFile(fileh, fileName)) {
00101             emit codeGenerated(c, false);
00102             return;
00103         }
00104         // write Header file
00105         writeHeaderFile(c, fileh);
00106         fileh.close();
00107     }
00108 
00109     // Determine whether the implementation file is required.
00110     // (It is not required if the class is an enumeration.)
00111     bool need_impl = true;
00112     if (c->getBaseType() == Uml::ot_Enum) {
00113         need_impl = false;
00114     }
00115     if (need_impl) {
00116         fileName.replace( QRegExp(".h$"), ".cpp");
00117         if( !openFile(filecpp, fileName)) {
00118             emit codeGenerated(c, false);
00119             return;
00120         }
00121         // write Source file
00122         writeSourceFile(c, filecpp);
00123         filecpp.close();
00124     }
00125 
00126     // Wrap up: free m_classifierInfo, emit done code
00127     m_classifierInfo = 0;
00128 
00129     emit codeGenerated(c, true);
00130 
00131 }
00132 
00133 void CppWriter::writeHeaderFile (UMLClassifier *c, QFile &fileh) {
00134 
00135     // open stream for writing
00136     QTextStream h (&fileh);
00137 
00138     // up the indent level to one
00139     m_indentLevel = 1;
00140 
00141     // write header blurb
00142     QString str = getHeadingFile(".h");
00143     if(!str.isEmpty()) {
00144         str.replace(QRegExp("%filename%"),m_classifierInfo->fileName + ".h");
00145         str.replace(QRegExp("%filepath%"),fileh.name());
00146         h << str<< m_endl;
00147     }
00148 
00149     // Write the hash define stuff to prevent multiple parsing/inclusion of header
00150     QString hashDefine = m_classifierInfo->className.upper().simplifyWhiteSpace().replace(QRegExp(" "),  "_");
00151     writeBlankLine(h);
00152     h << "#ifndef "<< hashDefine + "_H" << m_endl;
00153     h << "#define "<< hashDefine + "_H" << m_endl;
00154 
00155     writeClassDecl(c, h);
00156 
00157     // last thing..close our hashdefine
00158     h << m_endl << "#endif // " << hashDefine + "_H" << m_endl;
00159 
00160 }
00161 
00162 void CppWriter::writeHeaderAccessorMethodDecl(UMLClassifier *c, Uml::Visibility permitScope, QTextStream &stream)
00163 {
00164 
00165     // attributes
00166     writeHeaderAttributeAccessorMethods(permitScope, true, stream); // write static attributes first
00167     writeHeaderAttributeAccessorMethods(permitScope, false, stream);
00168 
00169     // associations
00170     writeAssociationMethods(m_classifierInfo->plainAssociations, permitScope,
00171                             true, INLINE_ASSOCIATION_METHODS, true, c->getID(), stream);
00172     writeAssociationMethods(m_classifierInfo->uniAssociations, permitScope,
00173                             true, INLINE_ASSOCIATION_METHODS, true, c->getID(), stream);
00174     writeAssociationMethods(m_classifierInfo->aggregations, permitScope,
00175                             true,  INLINE_ASSOCIATION_METHODS, true, c->getID(), stream);
00176     writeAssociationMethods(m_classifierInfo->compositions, permitScope,
00177                             true, INLINE_ASSOCIATION_METHODS, false, c->getID(), stream);
00178 
00179     writeBlankLine(stream);
00180 
00181 }
00182 
00183 void CppWriter::writeHeaderFieldDecl(UMLClassifier *c, Uml::Visibility permitScope, QTextStream &stream)
00184 {
00185     // attributes
00186     writeAttributeDecls(permitScope, true, stream); // write static attributes first
00187     writeAttributeDecls(permitScope, false, stream);
00188 
00189     // associations
00190     writeAssociationDecls(m_classifierInfo->plainAssociations, permitScope, c->getID(), stream);
00191     writeAssociationDecls(m_classifierInfo->uniAssociations, permitScope, c->getID(), stream);
00192     writeAssociationDecls(m_classifierInfo->aggregations, permitScope, c->getID(), stream);
00193     writeAssociationDecls(m_classifierInfo->compositions, permitScope, c->getID(), stream);
00194 
00195 }
00196 
00197 void CppWriter::writeSourceFile (UMLClassifier *c, QFile &filecpp ) {
00198 
00199     // open stream for writing
00200     QTextStream cpp (&filecpp);
00201 
00202     // set the starting indentation at zero
00203     m_indentLevel = 0;
00204 
00205     //try to find a heading file (license, coments, etc)
00206     QString str;
00207     str = getHeadingFile(".cpp");
00208     if(!str.isEmpty()) {
00209         str.replace(QRegExp("%filename%"),m_classifierInfo->fileName + ".cpp");
00210         str.replace(QRegExp("%filepath%"),filecpp.name());
00211         cpp << str << m_endl;
00212     }
00213 
00214     // IMPORT statements
00215     // Q: Why all utils? Isnt just List and Vector the only classes we are using?
00216     // Our import *should* also look at operations, and check that objects being
00217     // used arent in another package (and thus need to be explicitly imported here).
00218     cpp << "#include \"" << m_classifierInfo->className << ".h\"" << m_endl;
00219     writeBlankLine(cpp);
00220 
00221     if (c->getVisibility() == Uml::Visibility::Implementation) {
00222         writeClassDecl(c, cpp);
00223     }
00224 
00225     // Start body of class
00226 
00227     // Constructors: anything we more we need to do here ?
00228     //
00229     if(!m_classifierInfo->isInterface)
00230         writeConstructorMethods(cpp);
00231 
00232     // METHODS
00233     //
00234 
00235     // write comment for section IF needed
00236     QString indent = getIndent();
00237     if (forceDoc() || m_classifierInfo->hasAccessorMethods || m_classifierInfo->hasOperationMethods)
00238     {
00239 
00240         writeComment(" ", indent, cpp);
00241         writeComment("Methods", indent, cpp);
00242         writeComment(" ", indent, cpp);
00243         writeBlankLine(cpp);
00244         writeBlankLine(cpp);
00245     }
00246 
00247     // write comment for sub-section IF needed
00248     if (forceDoc() || m_classifierInfo->hasAccessorMethods )
00249     {
00250         writeComment("Accessor methods", indent, cpp);
00251         writeComment(" ", indent, cpp);
00252         writeBlankLine(cpp);
00253     }
00254 
00255     // Accessor methods for attributes
00256     const bool bInlineAccessors = policyExt()->getAccessorsAreInline();
00257     if (!bInlineAccessors && m_classifierInfo->hasAttributes)
00258     {
00259         writeAttributeMethods(&(m_classifierInfo->static_atpub), Uml::Visibility::Public, false, true, !bInlineAccessors, cpp);
00260         writeAttributeMethods(&(m_classifierInfo->atpub), Uml::Visibility::Public, false, false, !bInlineAccessors, cpp);
00261         writeAttributeMethods(&(m_classifierInfo->static_atprot), Uml::Visibility::Protected, false, true, !bInlineAccessors, cpp);
00262         writeAttributeMethods(&(m_classifierInfo->atprot), Uml::Visibility::Protected, false, false, !bInlineAccessors, cpp);
00263         writeAttributeMethods(&(m_classifierInfo->static_atpriv), Uml::Visibility::Private, false, true, !bInlineAccessors, cpp);
00264         writeAttributeMethods(&(m_classifierInfo->atpriv), Uml::Visibility::Private, false, false, !bInlineAccessors, cpp);
00265     }
00266 
00267     // accessor methods for associations
00268 
00269     // public
00270     writeAssociationMethods(m_classifierInfo->plainAssociations, Uml::Visibility::Public, false,
00271                             !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
00272     writeAssociationMethods(m_classifierInfo->uniAssociations, Uml::Visibility::Public, false,
00273                             !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
00274     writeAssociationMethods(m_classifierInfo->aggregations, Uml::Visibility::Public, false,
00275                             !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
00276     writeAssociationMethods(m_classifierInfo->compositions, Uml::Visibility::Public, false,
00277                             !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
00278 
00279     // protected
00280     writeAssociationMethods(m_classifierInfo->plainAssociations, Uml::Visibility::Protected, false,
00281                             !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
00282     writeAssociationMethods(m_classifierInfo->uniAssociations, Uml::Visibility::Protected, false,
00283                             !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
00284     writeAssociationMethods(m_classifierInfo->aggregations, Uml::Visibility::Protected, false,
00285                             !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
00286     writeAssociationMethods(m_classifierInfo->compositions, Uml::Visibility::Protected, false,
00287                             !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
00288 
00289 
00290     // private
00291     writeAssociationMethods(m_classifierInfo->plainAssociations, Uml::Visibility::Private, false,
00292                             !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
00293     writeAssociationMethods(m_classifierInfo->uniAssociations, Uml::Visibility::Private, false,
00294                             !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
00295     writeAssociationMethods(m_classifierInfo->aggregations, Uml::Visibility::Private, false,
00296                             !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
00297     writeAssociationMethods(m_classifierInfo->compositions, Uml::Visibility::Private, false,
00298                             !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
00299     writeBlankLine(cpp);
00300 
00301     // Other operation methods -- all other operations are now written
00302     //
00303 
00304     // write comment for sub-section IF needed
00305     if (forceDoc() || m_classifierInfo->hasOperationMethods)
00306     {
00307         writeComment("Other methods", indent, cpp);
00308         writeComment(" ", indent, cpp);
00309         writeBlankLine(cpp);
00310     }
00311 
00312     if(!policyExt()->getOperationsAreInline())
00313     {
00314         writeOperations(c,false,Uml::Visibility::Public,cpp);
00315         writeOperations(c,false,Uml::Visibility::Protected,cpp);
00316         writeOperations(c,false,Uml::Visibility::Private,cpp);
00317     }
00318 
00319     // Yep, bringing up the back of the bus, our initialization method for attributes
00320     writeInitAttibuteMethod (cpp);
00321 
00322     writeBlankLine(cpp);
00323 
00324 }
00325 
00326 void CppWriter::writeClassDecl(UMLClassifier *c, QTextStream &cpp)
00327 {
00328     UMLClassifierList superclasses = m_classifierInfo->superclasses;
00329     for(UMLClassifier *classifier = superclasses.first(); classifier ;classifier = superclasses.next()) {
00330         QString headerName = findFileName(classifier, ".h");
00331         if (!headerName.isEmpty()) {
00332             cpp << "#include \"" << headerName << "\"" << m_endl;
00333         }
00334     }
00335 
00336     writeBlankLine(cpp);
00337     cpp << "#include " << policyExt()->getStringClassNameInclude() << m_endl;
00338     if(m_classifierInfo->hasVectorFields)
00339     {
00340         cpp << "#include " << policyExt()->getVectorClassNameInclude() << m_endl;
00341         writeBlankLine(cpp);
00342     }
00343 
00344     if(m_classifierInfo->hasAssociations)
00345     {
00346         // write all includes we need to include other classes, that arent us.
00347         printAssociationIncludeDecl (m_classifierInfo->plainAssociations, c->getID(), cpp);
00348         printAssociationIncludeDecl (m_classifierInfo->uniAssociations, c->getID(), cpp);
00349         printAssociationIncludeDecl (m_classifierInfo->aggregations, c->getID(), cpp);
00350         printAssociationIncludeDecl (m_classifierInfo->compositions, c->getID(), cpp);
00351 
00352         writeBlankLine(cpp);
00353     }
00354 
00355 
00356     for(UMLClassifier *classifier = superclasses.first(); classifier ; classifier = superclasses.next()) {
00357         if(classifier->getPackage()!=c->getPackage() && !classifier->getPackage().isEmpty()) {
00358             cpp << "using " << cleanName(classifier->getPackage()) << "::" << cleanName(classifier->getName()) << ";" << m_endl;
00359         }
00360     }
00361 
00362     if(!c->getPackage().isEmpty() && policyExt()->getPackageIsNamespace())
00363         cpp << m_endl << "namespace " << cleanName(c->getPackage()) << " {" << m_endl << m_endl;
00364 
00365     //Write class Documentation if there is somthing or if force option
00366     if(forceDoc() || !c->getDoc().isEmpty()) {
00367         cpp << m_endl << "";
00371         writeBlankLine(cpp);
00372         writeBlankLine(cpp);
00373     }
00374 
00375     //check if class is abstract and / or has abstract methods
00376     if((c->getAbstract() || m_classifierInfo->isInterface )
00377             && !hasAbstractOps(c))
00378         cpp << "/******************************* Abstract Class ****************************" << m_endl
00379         <<m_classifierInfo->className << " does not have any pure virtual methods, but its author" << m_endl
00380         <<"  defined it as an abstract class, so you should not use it directly." << m_endl
00381         <<"  Inherit from it instead and create only objects from the derived classes" << m_endl
00382         <<"*****************************************************************************/" << m_endl << m_endl;
00383 
00384     if (c->getBaseType() == Uml::ot_Enum) {
00385         UMLClassifierListItemList litList = c->getFilteredList(Uml::ot_EnumLiteral);
00386         uint i = 0;
00387         cpp << "enum " << m_classifierInfo->className << " {" << m_endl;
00388         for (UMLClassifierListItem *lit = litList.first(); lit; lit = litList.next()) {
00389             QString enumLiteral = cleanName(lit->getName());
00390             cpp << getIndent() << enumLiteral;
00391             if (++i < litList.count())
00392                 cpp << ",";
00393             cpp << m_endl;
00394         }
00395         cpp << m_endl << "};" << m_endl;  // end of class header
00396         if(!c->getPackage().isEmpty() && policyExt()->getPackageIsNamespace())
00397             cpp << "}  // end of package namespace" << m_endl;
00398         return;
00399     }
00400 
00401     // Generate template parameters.
00402     UMLTemplateList template_params = c->getTemplateList();
00403     if (template_params.count()) {
00404         cpp << "template<";
00405         for (UMLTemplate *t = template_params.first(); t; ) {
00406             QString formalName = t->getName();
00407             QString typeName = t->getTypeName();
00408             cpp << typeName << " " << formalName;
00409             if ((t = template_params.next()) != NULL)
00410                 cpp << ", ";
00411         }
00412         cpp << ">" << m_endl;
00413     }
00414 
00415     cpp << "class " << m_classifierInfo->className;
00416     if (m_classifierInfo->superclasses.count() > 0)
00417         cpp << " : ";
00418     uint numOfSuperClasses = m_classifierInfo->superclasses.count();
00419     uint i = 0;
00420     for (UMLClassifier *superClass = m_classifierInfo->superclasses.first();
00421             superClass ; superClass = m_classifierInfo->superclasses.next())
00422     {
00423         i++;
00424         if (superClass->getAbstract() || superClass->isInterface())
00425             cpp << "virtual ";
00426         cpp << "public " << cleanName(superClass->getName());
00427         if (i < numOfSuperClasses)
00428             cpp << ", ";
00429     }
00430 
00431     cpp << m_endl << "{" << m_endl; // begin the body of the class
00432 
00433 
00434     //declarations of operations
00435     //
00436 
00437     //
00438     // write out field and operations decl grouped by visibility
00439     //
00440 
00441     // PUBLIC attribs/methods
00442     cpp << "public:" << m_endl << m_endl; // print visibility decl.
00443     // for public: constructors are first ops we print out
00444     if(!m_classifierInfo->isInterface)
00445         writeConstructorDecls(cpp);
00446     writeHeaderFieldDecl(c,Uml::Visibility::Public, cpp);
00447     writeHeaderAccessorMethodDecl(c, Uml::Visibility::Public, cpp);
00448     writeOperations(c,true,Uml::Visibility::Public,cpp);
00449 
00450     // PROTECTED attribs/methods
00451     //
00452     cpp << "protected" << ":" << m_endl << m_endl; // print visibility decl.
00453     writeHeaderFieldDecl(c,Uml::Visibility::Protected, cpp);
00454     writeHeaderAccessorMethodDecl(c, Uml::Visibility::Protected, cpp);
00455     writeOperations(c,true,Uml::Visibility::Protected,cpp);
00456 
00457     // PRIVATE attribs/methods
00458     //
00459     cpp << "private" << ":" << m_endl << m_endl; // print visibility decl.
00460     writeHeaderFieldDecl(c,Uml::Visibility::Private, cpp);
00461     writeHeaderAccessorMethodDecl(c, Uml::Visibility::Private, cpp);
00462     writeOperations(c,true,Uml::Visibility::Private,cpp);
00463     writeInitAttibuteDecl(cpp); // this is always private, used by constructors to initialize class
00464 
00465     // end of class header
00466     cpp << m_endl << "};" << m_endl;
00467 
00468     // end of class namespace, if any
00469     if(!c->getPackage().isEmpty() && policyExt()->getPackageIsNamespace())
00470         cpp << "}; // end of package namespace" << m_endl;
00471 
00472 }
00473 
00474 void CppWriter::writeAttributeDecls (Uml::Visibility visibility, bool writeStatic, QTextStream &stream )
00475 {
00476 
00477     if(m_classifierInfo->isInterface)
00478         return;
00479 
00480     UMLAttributeList * list;
00481     switch (visibility)
00482     {
00483       case Uml::Visibility::Private:
00484         if(writeStatic)
00485             list = &(m_classifierInfo->static_atpriv);
00486         else
00487             list = &(m_classifierInfo->atpriv);
00488         break;
00489 
00490       case Uml::Visibility::Protected:
00491         if(writeStatic)
00492             list = &(m_classifierInfo->static_atprot);
00493         else
00494             list = &(m_classifierInfo->atprot);
00495         break;
00496 
00497       case Uml::Visibility::Public:
00498     default:
00499         if(writeStatic)
00500             list = &(m_classifierInfo->static_atpub);
00501         else
00502             list = &(m_classifierInfo->atpub);
00503         break;
00504     }
00505 
00506     //write documentation
00507     if(forceDoc() || list->count() > 0)
00508     {
00509         QString strVis = capitalizeFirstLetter(visibility.toString());
00510         QString strStatic = writeStatic ? "Static ":"";
00511         writeComment(strStatic + strVis + " attributes",getIndent(), stream);
00512         writeComment(" ",getIndent(), stream);
00513         writeBlankLine(stream);
00514     }
00515 
00516     if (list->count() > 0) {
00517 
00518         // write attrib declarations now
00519         bool isFirstAttrib = true;
00520         QString documentation;
00521         for(UMLAttribute *at=list->first(); at; at=list->next())
00522         {
00523 
00524             //                  bool noPriorDocExists = documentation.isEmpty();
00525             documentation = at->getDoc();
00526 
00527             // add a line for code clarity IF PRIOR attrib has comment on it
00528             // OR this line has documentation
00529             //                  if(!isFirstAttrib && (!documentation.isEmpty()||!noPriorDocExists))
00530             //                          writeBlankLine(stream);
00531 
00532             isFirstAttrib = false;
00533 
00534             QString varName = getAttributeVariableName(at);
00535 
00536             QString staticValue = at->getStatic() ? "static " : "";
00537             QString typeName = fixTypeName(at->getTypeName());
00538             if(!documentation.isEmpty())
00539                 writeComment(documentation, getIndent(), stream);
00540             stream << getIndent() << staticValue << typeName << " " << varName << ";" << m_endl;
00541 
00542         }
00543 
00544         /*
00545                         if(list->count() > 0)
00546                                 writeBlankLine(stream);
00547         */
00548 
00549     }
00550 
00551 }
00552 
00553 void CppWriter::writeHeaderAttributeAccessorMethods (Uml::Visibility visibility, bool writeStatic, QTextStream &stream )
00554 {
00555     // check the current policy about generate accessors as public
00556     UMLAttributeList * list;
00557     switch (visibility)
00558     {
00559       case Uml::Visibility::Private:
00560         if(writeStatic)
00561             list = &(m_classifierInfo->static_atpriv);
00562         else
00563             list = &(m_classifierInfo->atpriv);
00564         break;
00565 
00566       case Uml::Visibility::Protected:
00567         if(writeStatic)
00568             list = &(m_classifierInfo->static_atprot);
00569         else
00570             list = &(m_classifierInfo->atprot);
00571         break;
00572 
00573       case Uml::Visibility::Public:
00574     default:
00575         if(writeStatic)
00576             list = &(m_classifierInfo->static_atpub);
00577         else
00578             list = &(m_classifierInfo->atpub);
00579         break;
00580     }
00581 
00582     // switch to public
00583     if (visibility != Uml::Visibility::Public)
00584         stream << "public:" << m_endl << m_endl;
00585 
00586     // write accessor methods for attribs we found
00587     writeAttributeMethods(list, visibility, true, false, policyExt()->getAccessorsAreInline(), stream);
00588 
00589     // switch back to previous vis.
00590     if (visibility != Uml::Visibility::Public)
00591         stream << visibility.toString() << ":" << m_endl << m_endl;
00592 }
00593 
00594 // this is for writing *source* or *header* file attribute methods
00595 //
00596 void CppWriter::writeAttributeMethods(UMLAttributeList *attribs,
00597                                       Uml::Visibility visibility, bool isHeaderMethod,
00598                                       bool isStatic,
00599                                       bool writeMethodBody, QTextStream &stream)
00600 {
00601 
00602     if (!policyExt()->getAutoGenerateAccessors())
00603         return;
00604 
00605     if (forceDoc() || attribs->count() > 0)
00606     {
00607         QString strVis = capitalizeFirstLetter(visibility.toString());
00608         QString strStatic = (isStatic ? " static" : "");
00609         writeBlankLine(stream);
00610         writeComment(strVis + strStatic + " attribute accessor methods",getIndent(),stream);
00611         writeComment(" ",getIndent(), stream);
00612         writeBlankLine(stream);
00613     }
00614 
00615     // return now if NO attributes to work on
00616     if (attribs->count() == 0)
00617         return;
00618 
00619     UMLAttribute *at;
00620     for(at=attribs->first(); at; at=attribs->next())
00621     {
00622 
00623         QString varName = getAttributeVariableName(at);
00624         QString methodBaseName = cleanName(at->getName());
00625 
00626         // force capitalizing the field name, this is silly,
00627         // from what I can tell, this IS the default behavior for
00628         // cleanName. I dunno why its not working -b.t.
00629         methodBaseName = methodBaseName.stripWhiteSpace();
00630         methodBaseName.replace(0,1,methodBaseName.at(0).upper());
00631 
00632         writeSingleAttributeAccessorMethods(at->getTypeName(), varName,
00633                                             methodBaseName, at->getDoc(), Uml::chg_Changeable, isHeaderMethod,
00634                                             at->getStatic(), writeMethodBody, stream);
00635     }
00636 
00637 }
00638 
00639 void CppWriter::writeComment(const QString &comment, const QString &myIndent, QTextStream &cpp)
00640 {
00641     // in the case we have several line comment..
00642     // NOTE: this part of the method has the problem of adopting UNIX newline,
00643     // need to resolve for using with MAC/WinDoze eventually I assume
00644     if (comment.contains(QRegExp("\n"))) {
00645 
00646         QStringList lines = QStringList::split( "\n", comment);
00647         for(uint i= 0; i < lines.count(); i++)
00648         {
00649             cpp << myIndent << "// " << lines[i] << m_endl;
00650         }
00651     } else {
00652         // this should be more fancy in the future, breaking it up into 80 char
00653         // lines so that it doesn't look too bad
00654         cpp << myIndent << "// "<< comment << m_endl;
00655     }
00656 }
00657 
00658 void CppWriter::writeDocumentation(QString header, QString body, QString end, QTextStream &cpp)
00659 {
00660     writeBlankLine(cpp);
00661     QString indent = getIndent();
00662 
00663     cpp << indent << "" << m_endl;
00675 }
00676 
00677 void CppWriter::writeAssociationDecls(UMLAssociationList associations, Uml::Visibility permitScope, Uml::IDType id, QTextStream &h)
00678 {
00679 
00680     if( forceSections() || !associations.isEmpty() )
00681     {
00682         bool printRoleA = false, printRoleB = false;
00683         for(UMLAssociation *a = associations.first(); a; a = associations.next())
00684         {
00685 
00686             // it may seem counter intuitive, but you want to insert the role of the
00687             // *other* class into *this* class.
00688             if (a->getObjectId(Uml::A) == id && !a->getRoleName(Uml::B).isEmpty())
00689                 printRoleB = true;
00690 
00691             if (a->getObjectId(Uml::B) == id && !a->getRoleName(Uml::A).isEmpty())
00692                 printRoleA = true;
00693 
00694             // First: we insert documentaion for association IF it has either role AND some documentation (!)
00695             if ((printRoleA || printRoleB) && !(a->getDoc().isEmpty()))
00696                 writeComment(a->getDoc(), getIndent(), h);
00697 
00698             // print RoleB decl
00699             if (printRoleB && a->getVisibility(Uml::B) == permitScope)
00700             {
00701 
00702                 QString fieldClassName = cleanName(getUMLObjectName(a->getObject(Uml::B)));
00703                 writeAssociationRoleDecl(fieldClassName, a->getRoleName(Uml::B), a->getMulti(Uml::B), a->getRoleDoc(Uml::B), h);
00704             }
00705 
00706             // print RoleA decl
00707             if (printRoleA && a->getVisibility(Uml::A) == permitScope)
00708             {
00709                 QString fieldClassName = cleanName(getUMLObjectName(a->getObject(Uml::A)));
00710                 writeAssociationRoleDecl(fieldClassName, a->getRoleName(Uml::A), a->getMulti(Uml::A), a->getRoleDoc(Uml::A), h);
00711             }
00712 
00713             // reset for next association in our loop
00714             printRoleA = false;
00715             printRoleB = false;
00716         }
00717     }
00718 }
00719 
00720 void CppWriter::writeAssociationRoleDecl(QString fieldClassName, QString roleName, QString multi,
00721         QString doc, QTextStream &stream)
00722 {
00723     // ONLY write out IF there is a rolename given
00724     // otherwise its not meant to be declared in the code
00725     if (roleName.isEmpty())
00726         return;
00727 
00728     QString indent = getIndent();
00729 
00730     // always put space between this and prior decl, if any
00731     writeBlankLine(stream);
00732 
00733     if (!doc.isEmpty())
00734         writeComment(doc, indent, stream);
00735 
00736     // declare the association based on whether it is this a single variable
00737     // or a List (Vector). One day this will be done correctly with special
00738     // multiplicity object that we don't have to figure out what it means via regex.
00739     if(multi.isEmpty() || multi.contains(QRegExp("^[01]$")))
00740     {
00741         QString fieldVarName = "m_" + roleName.lower();
00742 
00743         // record this for later consideration of initialization IF the
00744         // multi value requires 1 of these objects
00745         if(ObjectFieldVariables.findIndex(fieldVarName) == -1 &&
00746                 multi.contains(QRegExp("^1$"))
00747           )
00748         {
00749             // ugh. UGLY. Storing variable name and its class in pairs.
00750             ObjectFieldVariables.append(fieldVarName);
00751             ObjectFieldVariables.append(fieldClassName);
00752         }
00753 
00754         stream << indent << fieldClassName << " * " << fieldVarName << ";" << m_endl;
00755     }
00756     else
00757     {
00758         QString fieldVarName = "m_" + roleName.lower() + "Vector";
00759 
00760         // record unique occurrences for later when we want to check
00761         // for initialization of this vector
00762         if(VectorFieldVariables.findIndex(fieldVarName) == -1)
00763             VectorFieldVariables.append(fieldVarName);
00764 
00765         stream << indent << policyExt()->getVectorClassName() <<"<" << fieldClassName << "*";
00766         stream << "> " << fieldVarName << ";" << m_endl;
00767     }
00768 }
00769 
00770 // for either source or header files
00771 void CppWriter::writeAssociationMethods (UMLAssociationList associations,
00772         Uml::Visibility permitVisib,
00773         bool isHeaderMethod,
00774         bool writeMethodBody,
00775         bool writePointerVar,
00776         Uml::IDType myID, QTextStream &stream)
00777 {
00778     if( forceSections() || !associations.isEmpty() )
00779     {
00780         for(UMLAssociation *a = associations.first(); a; a = associations.next())
00781         {
00782 
00783             // insert the methods to access the role of the other
00784             // class in the code of this one
00785             if (a->getObjectId(Uml::A) == myID && a->getVisibility(Uml::B) == permitVisib)
00786             {
00787                 // only write out IF there is a rolename given
00788                 if(!a->getRoleName(Uml::B).isEmpty()) {
00789                     QString fieldClassName = getUMLObjectName(a->getObject(Uml::B)) + (writePointerVar ? " *":"");
00790                     writeAssociationRoleMethod(fieldClassName,
00791                                                isHeaderMethod,
00792                                                writeMethodBody,
00793                                                a->getRoleName(Uml::B),
00794                                                a->getMulti(Uml::B), a->getRoleDoc(Uml::B),
00795                                                a->getChangeability(Uml::B), stream);
00796                 }
00797             }
00798 
00799             if (a->getObjectId(Uml::B) == myID && a->getVisibility(Uml::A) == permitVisib)
00800             {
00801                 // only write out IF there is a rolename given
00802                 if(!a->getRoleName(Uml::A).isEmpty()) {
00803                     QString fieldClassName = getUMLObjectName(a->getObject(Uml::A)) + (writePointerVar ? " *":"");
00804                     writeAssociationRoleMethod(fieldClassName,
00805                                                isHeaderMethod,
00806                                                writeMethodBody,
00807                                                a->getRoleName(Uml::A),
00808                                                a->getMulti(Uml::A),
00809                                                a->getRoleDoc(Uml::A),
00810                                                a->getChangeability(Uml::A),
00811                                                stream);
00812                 }
00813             }
00814 
00815         }
00816     }
00817 }
00818 
00819 void CppWriter::writeAssociationRoleMethod (const QString &fieldClassName,
00820         bool isHeaderMethod,
00821         bool writeMethodBody,
00822         const QString &roleName, const QString &multi,
00823         const QString &description, Uml::Changeability_Type change,
00824         QTextStream &stream)
00825 {
00826     if(multi.isEmpty() || multi.contains(QRegExp("^[01]$")))
00827     {
00828         QString fieldVarName = "m_" + roleName.lower();
00829         writeSingleAttributeAccessorMethods(fieldClassName, fieldVarName, roleName,
00830                                             description, change, isHeaderMethod, false, writeMethodBody, stream);
00831     }
00832     else
00833     {
00834         QString fieldVarName = "m_" + roleName.lower() + "Vector";
00835         writeVectorAttributeAccessorMethods(fieldClassName, fieldVarName, roleName,
00836                                             description, change, isHeaderMethod, writeMethodBody, stream);
00837     }
00838 }
00839 
00840 void CppWriter::writeVectorAttributeAccessorMethods (
00841         const QString &fieldClassName, const QString &fieldVarName,
00842         const QString &fieldName, const QString &description,
00843         Uml::Changeability_Type changeType,
00844         bool isHeaderMethod,
00845         bool writeMethodBody,
00846         QTextStream &stream)
00847 {
00848 
00849     QString className = fixTypeName(fieldClassName);
00850     QString fldName = capitalizeFirstLetter(fieldName);
00851     QString indent = getIndent();
00852 
00853     // ONLY IF changeability is NOT Frozen
00854     if (changeType != Uml::chg_Frozen)
00855     {
00856         writeDocumentation("Add a " + fldName + " object to the " + fieldVarName + " List",description,"",stream);
00857         stream << indent << "void ";
00858         if(!isHeaderMethod)
00859             stream << m_classifierInfo->className << "::";
00860         stream << "add" << fldName << " ( " << className << " add_object )";
00861         if (writeMethodBody) {
00862             QString method = VECTOR_METHOD_APPEND;
00863             method.replace(QRegExp("%VARNAME%"),fieldVarName);
00864             method.replace(QRegExp("%VECTORTYPENAME%"), policyExt()->getVectorClassName());
00865             method.replace(QRegExp("%ITEMCLASS%"),className);
00866             stream << indent << " {" << m_endl;
00867             m_indentLevel++;
00868             printTextAsSeparateLinesWithIndent(method,getIndent(),stream);
00869             m_indentLevel--;
00870             stream << indent << "}" << m_endl;
00871         } else
00872             stream << ";" << m_endl;
00873     }
00874 
00875     // ONLY IF changeability is Changeable
00876     if (changeType == Uml::chg_Changeable)
00877     {
00878         writeDocumentation("Remove a " + fldName + " object from " + fieldVarName + " List",
00879                            description, "", stream);
00880         stream << indent << "void ";
00881         if(!isHeaderMethod)
00882             stream << m_classifierInfo->className << "::";
00883         stream << "remove" << fldName << " ( " << className << " remove_object )";
00884         if (writeMethodBody) {
00885             QString method = VECTOR_METHOD_REMOVE;
00886             method.replace(QRegExp("%VARNAME%"),fieldVarName);
00887             method.replace(QRegExp("%VECTORTYPENAME%"), policyExt()->getVectorClassName());
00888             method.replace(QRegExp("%ITEMCLASS%"),className);
00889             stream << indent << " {" << m_endl;
00890             m_indentLevel++;
00891             printTextAsSeparateLinesWithIndent(method,getIndent(),stream);
00892             m_indentLevel--;
00893             stream << indent << "}" << m_endl;
00894         } else
00895             stream << ";" << m_endl;
00896     }
00897 
00898     // always allow getting the list of stuff
00899     QString returnVarName = policyExt()->getVectorClassName() + '<' + className + '>';
00900     writeDocumentation("Get the list of " + fldName + " objects held by " + fieldVarName,
00901                        description,
00902                        "@return " + returnVarName + " list of " + fldName + " objects held by " + fieldVarName,
00903                        stream);
00904     stream << indent << returnVarName << " ";
00905     if(!isHeaderMethod)
00906         stream << m_classifierInfo->className << "::";
00907     stream << "get" << fldName << "List ( )";
00908     if(writeMethodBody) {
00909         stream << indent << " {" << m_endl;
00910         m_indentLevel++;
00911         stream << getIndent() << "return " << fieldVarName << ";" << m_endl;
00912         m_indentLevel--;
00913         stream << indent << "}" << m_endl;
00914     } else
00915         stream << ";" << m_endl;
00916 
00917 }
00918 
00919 
00920 void CppWriter::writeSingleAttributeAccessorMethods(
00921         const QString &fieldClassName, const QString& fieldVarName,
00922         const QString &fieldName, const QString &description,
00923         Uml::Changeability_Type change,
00924         bool isHeaderMethod,
00925         bool isStatic,
00926         bool writeMethodBody,
00927         QTextStream &stream)
00928 {
00929 
00930     // DON'T write this IF its a source method AND writeMethodBody is "false"
00931     if(!isHeaderMethod && !writeMethodBody)
00932         return;
00933 
00934     QString className = fixTypeName(fieldClassName);
00935     QString fldName = capitalizeFirstLetter(fieldName);
00936     QString indent = getIndent();
00937 
00938     // set method
00939     if (change == Uml::chg_Changeable && !isStatic) {
00940         writeDocumentation("Set the value of " + fieldVarName,description,"@param new_var the new value of " + fieldVarName,stream);
00941         stream << indent << "void ";
00942         if(!isHeaderMethod)
00943             stream << m_classifierInfo->className << "::";
00944         stream << "set" << fldName << " ( " << className << " new_var )";
00945 
00946         if(writeMethodBody) {
00947             stream << indent << " {" << m_endl;
00948             m_indentLevel++;
00949             stream << getIndent() << indent;
00950             m_indentLevel--;
00951             if(isStatic)
00952                 stream << m_classifierInfo->className << "::";
00953             stream << fieldVarName << " = new_var;" << m_endl;
00954             stream << indent << "}" << m_endl;
00955         } else
00956             stream << ";" << m_endl;
00957     }
00958 
00959     // get method
00960     writeDocumentation("Get the value of " + fieldVarName,description,"@return the value of " + fieldVarName,stream);
00961     stream << indent << className << " ";
00962     if(!isHeaderMethod)
00963         stream << m_classifierInfo->className << "::";
00964     stream << "get" << fldName << " ( )";
00965 
00966     if(writeMethodBody) {
00967         stream << indent << " {" << m_endl;
00968         m_indentLevel++;
00969         stream << getIndent() << "return ";
00970         m_indentLevel--;
00971         if(isStatic)
00972             stream << m_classifierInfo->className << "::";
00973         stream << fieldVarName << ";" << m_endl;
00974         stream << indent << "}";
00975     } else
00976         stream << ";" << m_endl;
00977 
00978     writeBlankLine(stream);
00979 }
00980 
00981 // one day, this should print out non-empty constructor operations too.
00982 void CppWriter::writeConstructorDecls(QTextStream &stream)
00983 {
00984     const bool generateEmptyConstructors =
00985         UMLApp::app()->getCommonPolicy()->getAutoGenerateConstructors();
00986     if (forceDoc() || generateEmptyConstructors)
00987     {
00988         writeComment("Constructors/Destructors", getIndent(), stream);
00989         writeComment(" ", getIndent(), stream);
00990         writeBlankLine(stream);
00991     }
00992     if (!generateEmptyConstructors)
00993         return;
00994 
00995     writeDocumentation("", "Empty Constructor", "", stream);
00996     stream << getIndent() << m_classifierInfo->className << " ( );" << m_endl;
00997     writeDocumentation("", "Empty Destructor", "", stream);
00998     stream << getIndent();
00999     stream << "virtual ~" << m_classifierInfo->className << " ( );" << m_endl;
01000     writeBlankLine(stream);
01001 }
01002 
01003 void CppWriter::writeInitAttibuteDecl (QTextStream &stream)
01004 {
01005     if (UMLApp::app()->getCommonPolicy()->getAutoGenerateConstructors() &&
01006         m_classifierInfo->hasAttributes)
01007         stream << getIndent() << "void initAttributes ( ) ;" << m_endl;
01008 }
01009 
01010 void CppWriter::writeInitAttibuteMethod (QTextStream &stream)
01011 {
01012     // only need to do this under certain conditions
01013     if (!UMLApp::app()->getCommonPolicy()->getAutoGenerateConstructors() ||
01014         !m_classifierInfo->hasAttributes)
01015         return;
01016 
01017     QString className = m_classifierInfo->className;
01018     QString indent = getIndent();
01019 
01020     stream << indent << "void " << className << "::" << "initAttributes ( ) {" << m_endl;
01021 
01022     m_indentLevel++;
01023     // first, initiation of fields derived from attributes
01024     UMLAttributeList* atl = m_classifierInfo->getAttList();
01025     for(UMLAttribute *at = atl->first(); at ; at = atl->next()) {
01026         if(!at->getInitialValue().isEmpty()) {
01027             QString varName = getAttributeVariableName(at);
01028             stream << getIndent() << varName << " = " << at->getInitialValue() << ";" << m_endl;
01029         }
01030     }
01031     // Now initialize the association related fields (e.g. vectors)
01032     if (!VECTOR_METHOD_INIT.isEmpty()) {
01033         QStringList::Iterator it;
01034         for( it = VectorFieldVariables.begin(); it != VectorFieldVariables.end(); ++it ) {
01035             QString fieldVarName = *it;
01036             QString method = VECTOR_METHOD_INIT;
01037             method.replace(QRegExp("%VARNAME%"),fieldVarName);
01038             method.replace(QRegExp("%VECTORTYPENAME%"), policyExt()->getVectorClassName());
01039             stream << getIndent() << method << m_endl;
01040         }
01041     }
01042 
01043     if (!OBJECT_METHOD_INIT.isEmpty()) {
01044         QStringList::Iterator it;
01045         for( it = ObjectFieldVariables.begin(); it != ObjectFieldVariables.end(); ++it ) {
01046             QString fieldVarName = *it;
01047             it++;
01048             QString fieldClassName = *it;
01049             QString method = OBJECT_METHOD_INIT;
01050             method.replace(QRegExp("%VARNAME%"),fieldVarName);
01051             method.replace(QRegExp("%ITEMCLASS%"),fieldClassName);
01052             stream << getIndent() << method << m_endl;
01053         }
01054     }
01055 
01056     // clean up
01057     ObjectFieldVariables.clear(); // shouldn't be needed?
01058     VectorFieldVariables.clear(); // shouldn't be needed?
01059 
01060     m_indentLevel--;
01061 
01062     stream << indent << "}" << m_endl;
01063 }
01064 
01065 // one day, this should print out non-empty constructor operations too.
01066 void CppWriter::writeConstructorMethods(QTextStream &stream)
01067 {
01068     const bool generateEmptyConstructors =
01069         UMLApp::app()->getCommonPolicy()->getAutoGenerateConstructors();
01070 
01071     if (forceDoc() || generateEmptyConstructors) {
01072         writeComment("Constructors/Destructors", getIndent(), stream);
01073         writeComment(" ", getIndent(), stream);
01074         writeBlankLine(stream);
01075     }
01076     if (!generateEmptyConstructors)
01077         return;
01078 
01079     QString className = m_classifierInfo->className;
01080     // empty constructor
01081     QString indent = getIndent();
01082     stream << indent << className << "::" << className << " ( ) {" << m_endl;
01083     if(m_classifierInfo->hasAttributes)
01084         stream << indent << indent << "initAttributes();" << m_endl;
01085     stream << indent << "}" << m_endl;
01086     writeBlankLine(stream);
01087 
01088     // empty destructor
01089     stream << getIndent() << className << "::~" << className << " ( ) { }" << m_endl;
01090     writeBlankLine(stream);
01091 }
01092 
01093 // IF the type is "string" we need to declare it as
01094 // the Java Object "String" (there is no string primative in Java).
01095 QString CppWriter::fixTypeName(const QString &string)
01096 {
01097     if (string.isEmpty())
01098         return "void";
01099     if (string == "string")
01100         return policyExt()->getStringClassName();
01101     return string;
01102 }
01103 
01104 void CppWriter::writeOperations(UMLClassifier *c, bool isHeaderMethod,
01105                                 Uml::Visibility permitScope, QTextStream &cpp) {
01106 
01107     UMLOperationList oplist;
01108 
01109     //sort operations by scope first and see if there are abstract methods
01110     UMLOperationList inputlist = c->getOpList();
01111     for (UMLOperation *op = inputlist.first(); op; op = inputlist.next()) {
01112         if (op->getVisibility() == permitScope) {
01113             oplist.append(op);
01114         }
01115     }
01116 
01117     // do people REALLY want these comments? Hmm.
01118     /*
01119       if(forceSections() || oppub.count())
01120       {
01121       writeComment("public operations",getIndent(),cpp);
01122         writeBlankLine(cpp);
01123       }
01124     */
01125     writeOperations(oplist,isHeaderMethod, cpp);
01126 
01127 }
01128 
01129 // write operation in either header or
01130 // a source file
01131 void CppWriter::writeOperations(UMLOperationList &oplist, bool isHeaderMethod, QTextStream &cpp) {
01132     QString className = m_classifierInfo->className;
01133     const bool generateEmptyConstructors =
01134         UMLApp::app()->getCommonPolicy()->getAutoGenerateConstructors();
01135 
01136     // generate method decl for each operation given
01137     for (UMLOperation *op = oplist.first(); op; op = oplist.next()) {
01138 
01139         QString returnStr;  // buffer for documentation
01140         QString methodReturnType;
01141         UMLAttributeList atl = op->getParmList();  // method parameters
01142 
01143         if (op->isConstructorOperation()) {
01144             if (generateEmptyConstructors && atl.count() == 0)
01145                 continue;  // it's already been written, see writeConstructor{Decls,Methods}
01146         } else if (op->isDestructorOperation()) {
01147             if (generateEmptyConstructors)
01148                 continue;  // it's already been written, see writeConstructor{Decls,Methods}
01149         } else {
01150             methodReturnType = fixTypeName(op->getTypeName());
01151             if(methodReturnType != "void")
01152                 returnStr += "@return " + methodReturnType + '\n';
01153         }
01154 
01155         QString str;
01156         if (op->getAbstract() || m_classifierInfo->isInterface) {
01157             if (isHeaderMethod) {
01158                 // declare abstract method as 'virtual'
01159                 str += "virtual ";
01160             }
01161         }
01162 
01163         // static declaration for header file
01164         if (isHeaderMethod && op->getStatic())
01165             str += "static ";
01166 
01167         // returntype of method
01168         str += methodReturnType + ' ';
01169 
01170         if (!isHeaderMethod)
01171             str += className + "::";
01172 
01173         str += cleanName(op->getName()) + " (";
01174 
01175         // generate parameters
01176         uint j = 0;
01177         for (UMLAttribute *at = atl.first(); at; at = atl.next(), j++) {
01178             QString typeName = fixTypeName(at->getTypeName());
01179             QString atName = cleanName(at->getName());
01180             str += typeName + ' ' + atName;
01181             const QString initVal = at->getInitialValue();
01182             if (! initVal.isEmpty())
01183                 str += " = " + initVal;
01184             if (j < atl.count() - 1)
01185                 str += ", ";
01186             returnStr += "@param  " + atName + ' ' + at->getDoc() + '\n';
01187         }
01188         str += " )";
01189 
01190         if (op->getConst())
01191             str += " const";
01192 
01193         // method body : only gets IF its not in a header
01194         if (isHeaderMethod && !policyExt()->getOperationsAreInline())
01195             str += ';'; // terminate now
01196         else
01197             str +=getIndent() + " {\n\n" + getIndent() + '}'; // empty method body
01198 
01199         // write it out
01200         writeDocumentation("", op->getDoc(), returnStr, cpp);
01201         cpp << getIndent() << str << m_endl;
01202         writeBlankLine(cpp);
01203     }
01204 }
01205 
01206 // To prevent circular including when both classifiers on either end
01207 // of an association have roles we need to have forward declaration of
01208 // the other class...but only IF its not THIS class (as could happen
01209 // in self-association relationship).
01210 void CppWriter::printAssociationIncludeDecl (UMLAssociationList list, Uml::IDType myId, QTextStream &stream)
01211 {
01212 
01213     for (UMLAssociation *a = list.first(); a; a = list.next()) {
01214         UMLClassifier *current = NULL;
01215         bool isFirstClass = true;
01216 
01217         // only use OTHER classes (e.g. we don't need to write includes for ourselves!!
01218         // AND only IF the roleName is defined, otherwise, its not meant to be noticed.
01219         if (a->getObjectId(Uml::A) == myId && !a->getRoleName(Uml::B).isEmpty()) {
01220             current = dynamic_cast<UMLClassifier*>(a->getObject(Uml::B));
01221         } else if (a->getObjectId(Uml::B) == myId && !a->getRoleName(Uml::A).isEmpty()) {
01222             current = dynamic_cast<UMLClassifier*>(a->getObject(Uml::A));
01223             isFirstClass = false;
01224         }
01225 
01226         // as header doc for this method indicates, we need to be a bit sophisticated on
01227         // how to declare some associations.
01228         if( current )
01229             if( !isFirstClass && !a->getRoleName(Uml::A).isEmpty() && !a->getRoleName(Uml::B).isEmpty())
01230                 stream << "class " << current->getName() << ";" << m_endl; // special case: use forward declaration
01231             else
01232                 stream << "#include \"" << current->getName() << ".h\"" << m_endl; // just the include statement
01233     }
01234 }
01235 
01236 QString CppWriter::fixInitialStringDeclValue(const QString &value, const QString &type)
01237 {
01238     QString val = value;
01239     // check for strings only
01240     if (!val.isEmpty() && type == policyExt()->getStringClassName()) {
01241         if (!val.startsWith("\""))
01242             val.prepend("\"");
01243         if (!val.endsWith("\""))
01244             val.append("\"");
01245     }
01246     return val;
01247 }
01248 
01249 // methods like this _shouldn't_ be needed IF we properly did things thruought the code.
01250 QString CppWriter::getUMLObjectName(UMLObject *obj)
01251 {
01252     return(obj!=0)?obj->getName():QString("NULL");
01253 }
01254 
01255 QString CppWriter::capitalizeFirstLetter(const QString &string)
01256 {
01257     // we could lowercase everything tostart and then capitalize? Nah, it would
01258     // screw up formatting like getMyRadicalVariable() to getMyradicalvariable(). Bah.
01259     QChar firstChar = string.at(0);
01260     return firstChar + string.mid(1);
01261 }
01262 
01263 void CppWriter::writeBlankLine(QTextStream &stream)
01264 {
01265     stream << m_endl;
01266 }
01267 
01268 void CppWriter::printTextAsSeparateLinesWithIndent (const QString &text, const QString &indent, QTextStream &stream)
01269 {
01270     if(text.isEmpty())
01271         return;
01272 
01273     QStringList lines = QStringList::split( "\n", text);
01274     for(uint i= 0; i < lines.count(); i++)
01275         stream << indent << lines[i] << m_endl;
01276 }
01277 
01278 QString CppWriter::getAttributeVariableName (UMLAttribute *at)
01279 {
01280     QString fieldName = "m_" + cleanName(at->getName());
01281     return fieldName;
01282 }
01283 
01284 QStringList CppWriter::defaultDatatypes() {
01285     return Codegen_Utils::cppDatatypes();
01286 }
01287 
01288 const QStringList CppWriter::reservedKeywords() const {
01289     return Codegen_Utils::reservedCppKeywords();
01290 }
01291 
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:56 2007 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003