00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "cppwriter.h"
00021
00022 #include <qfile.h>
00023 #include <qtextstream.h>
00024 #include <qregexp.h>
00025 #include <kdebug.h>
00026
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
00041
00042
00043 CppWriter::CppWriter()
00044 {
00045
00046
00047
00048
00049
00050
00051 VECTOR_METHOD_APPEND = "%VARNAME%.push_back(add_object);";
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 }";
00053 VECTOR_METHOD_INIT = QString();
00054
00055
00056
00057
00058
00059
00060 OBJECT_METHOD_INIT = "%VARNAME% = new %ITEMCLASS%( );";
00061
00062
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
00088 QString fileName = findFileName(c, ".h");
00089 if (fileName.isEmpty()) {
00090 emit codeGenerated(c, false);
00091 return;
00092 }
00093
00094
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
00105 writeHeaderFile(c, fileh);
00106 fileh.close();
00107 }
00108
00109
00110
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
00122 writeSourceFile(c, filecpp);
00123 filecpp.close();
00124 }
00125
00126
00127 m_classifierInfo = 0;
00128
00129 emit codeGenerated(c, true);
00130
00131 }
00132
00133 void CppWriter::writeHeaderFile (UMLClassifier *c, QFile &fileh) {
00134
00135
00136 QTextStream h (&fileh);
00137
00138
00139 m_indentLevel = 1;
00140
00141
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
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
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
00166 writeHeaderAttributeAccessorMethods(permitScope, true, stream);
00167 writeHeaderAttributeAccessorMethods(permitScope, false, stream);
00168
00169
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
00186 writeAttributeDecls(permitScope, true, stream);
00187 writeAttributeDecls(permitScope, false, stream);
00188
00189
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
00200 QTextStream cpp (&filecpp);
00201
00202
00203 m_indentLevel = 0;
00204
00205
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
00215
00216
00217
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
00226
00227
00228
00229 if(!m_classifierInfo->isInterface)
00230 writeConstructorMethods(cpp);
00231
00232
00233
00234
00235
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
00248 if (forceDoc() || m_classifierInfo->hasAccessorMethods )
00249 {
00250 writeComment("Accessor methods", indent, cpp);
00251 writeComment(" ", indent, cpp);
00252 writeBlankLine(cpp);
00253 }
00254
00255
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
00268
00269
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
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
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
00302
00303
00304
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
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
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
00366 if(forceDoc() || !c->getDoc().isEmpty()) {
00367 cpp << m_endl << "";
00371 writeBlankLine(cpp);
00372 writeBlankLine(cpp);
00373 }
00374
00375
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;
00396 if(!c->getPackage().isEmpty() && policyExt()->getPackageIsNamespace())
00397 cpp << "} // end of package namespace" << m_endl;
00398 return;
00399 }
00400
00401
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 << "};
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
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
00519 bool isFirstAttrib = true;
00520 QString documentation;
00521 for(UMLAttribute *at=list->first(); at; at=list->next())
00522 {
00523
00524
00525 documentation = at->getDoc();
00526
00527
00528
00529
00530
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
00546
00547
00548
00549 }
00550
00551 }
00552
00553 void CppWriter::writeHeaderAttributeAccessorMethods (Uml::Visibility visibility, bool writeStatic, QTextStream &stream )
00554 {
00555
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
00583 if (visibility != Uml::Visibility::Public)
00584 stream << "public:" << m_endl << m_endl;
00585
00586
00587 writeAttributeMethods(list, visibility, true, false, policyExt()->getAccessorsAreInline(), stream);
00588
00589
00590 if (visibility != Uml::Visibility::Public)
00591 stream << visibility.toString() << ":" << m_endl << m_endl;
00592 }
00593
00594
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
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
00627
00628
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
00642
00643
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
00653
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
00687
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
00695 if ((printRoleA || printRoleB) && !(a->getDoc().isEmpty()))
00696 writeComment(a->getDoc(), getIndent(), h);
00697
00698
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
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
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
00724
00725 if (roleName.isEmpty())
00726 return;
00727
00728 QString indent = getIndent();
00729
00730
00731 writeBlankLine(stream);
00732
00733 if (!doc.isEmpty())
00734 writeComment(doc, indent, stream);
00735
00736
00737
00738
00739 if(multi.isEmpty() || multi.contains(QRegExp("^[01]$")))
00740 {
00741 QString fieldVarName = "m_" + roleName.lower();
00742
00743
00744
00745 if(ObjectFieldVariables.findIndex(fieldVarName) == -1 &&
00746 multi.contains(QRegExp("^1$"))
00747 )
00748 {
00749
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
00761
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
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
00784
00785 if (a->getObjectId(Uml::A) == myID && a->getVisibility(Uml::B) == permitVisib)
00786 {
00787
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
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
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
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
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
00931 if(!isHeaderMethod && !writeMethodBody)
00932 return;
00933
00934 QString className = fixTypeName(fieldClassName);
00935 QString fldName = capitalizeFirstLetter(fieldName);
00936 QString indent = getIndent();
00937
00938
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
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
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
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;
01233 }
01234 }
01235
01236 QString CppWriter::fixInitialStringDeclValue(const QString &value, const QString &type)
01237 {
01238 QString val = value;
01239
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
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
01258
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