umbrello API Documentation

dwriter.cpp

00001 
00002 /***************************************************************************
00003  *                                                                         *
00004  *   This program is free software; you can redistribute it and/or modify  *
00005  *   it under the terms of the GNU General Public License as published by  *
00006  *   the Free Software Foundation; either version 2 of the License, or     *
00007  *   (at your option) any later version.                                   *
00008  *                                                                         *
00009  *   copyright (C) 2007 Jari-Matti Mäkelä <jmjm@iki.fi>                    *
00010  *   Umbrello UML Modeller Authors <uml-devel@uml.sf.net>                  *
00011  ***************************************************************************/
00012 
00013 /***************************************************************************
00014     This is the "old" code generator that does not support code editing
00015     in the Modeller but uses significantly less file space because the
00016     source code is not replicated in the XMI file.
00017  ***************************************************************************/
00018 
00019 // own header
00020 #include "dwriter.h"
00021 // qt includes
00022 #include <qfile.h>
00023 #include <qstringlist.h>
00024 #include <qtextstream.h>
00025 #include <qregexp.h>
00026 // kde includes
00027 #include <kdebug.h>
00028 // app includes
00029 #include "../umldoc.h"
00030 #include "../classifier.h"
00031 #include "../operation.h"
00032 #include "../attribute.h"
00033 #include "../association.h"
00034 #include "../template.h"
00035 #include "../umltemplatelist.h"
00036 
00037 DWriter::DWriter() {
00038     startline = m_endl + m_indentation;
00039 }
00040 
00041 DWriter::~DWriter() {}
00042 
00043 Uml::Programming_Language DWriter::getLanguage() {
00044     return Uml::pl_D;
00045 }
00046 
00047 // FIXME: doesn't work yet
00048 void DWriter::writeModuleDecl(UMLClassifier *c, QTextStream &d) {
00049     if(!c->getPackage().isEmpty())
00050         d << "module " << c->getPackage() << ";" << m_endl;
00051 
00052     writeBlankLine(d);
00053 }
00054 
00055 void DWriter::writeModuleImports(UMLClassifier *c, QTextStream &d) {
00056     // another preparation, determine what we have
00057     UMLAssociationList associations = c->getSpecificAssocs(Uml::at_Association); // BAD! only way to get "general" associations.
00058     UMLAssociationList uniAssociations = c->getUniAssociationToBeImplemented();
00059 
00060     UMLAssociationList aggregations = c->getAggregations();
00061     UMLAssociationList compositions = c->getCompositions();
00062 
00063     bool hasAssociations = aggregations.count() + associations.count() +
00064          compositions.count() + uniAssociations.count() > 0;
00065 
00066     if (hasAssociations) {
00067         // import tango, if that mode is set
00068         writeBlankLine(d);
00069     }
00070 
00071     //only import classes in a different package as this class
00072     UMLPackageList imports;
00073     findObjectsRelated(c, imports);
00074     for (UMLPackage *con = imports.first(); con; con = imports.next()) {
00075         if (con->getBaseType() == Uml::ot_Datatype)
00076             continue;
00077         QString pkg = con->getPackage();
00078         if (!pkg.isEmpty() && pkg != c->getPackage())
00079             d << "import " << pkg << "." << cleanName(con->getName()) << ";"
00080             << m_endl;
00081     }
00082 
00083     writeBlankLine(d);
00084 }
00085 
00086 void DWriter::writeClass(UMLClassifier *c) {
00087     if (!c) {
00088         kDebug()<<"Cannot write class of NULL concept!\n";
00089         return;
00090     }
00091 
00092     isInterface = c->isInterface();
00093 
00094     QString fileName = cleanName(c->getName().lower());
00095 
00096     //find an appropriate name for our file
00097     fileName = findFileName(c, ".d");
00098     if (fileName.isEmpty()) {
00099         emit codeGenerated(c, false);
00100         return;
00101     }
00102 
00103     // check that we may open that file for writing
00104     QFile file;
00105     if ( !openFile(file, fileName) ) {
00106         emit codeGenerated(c, false);
00107         return;
00108     }
00109 
00110     // open text stream to file
00111     QTextStream d(&file);
00112 
00113     //try to find a heading file (license, coments, etc)
00114     QString str;
00115     str = getHeadingFile(".d");
00116     if(!str.isEmpty()) {
00117         str.replace(QRegExp("%filename%"),fileName);
00118         str.replace(QRegExp("%filepath%"),file.name());
00119         d<<str<<m_endl;
00120     }
00121 
00122     // source file begins with the module declaration
00123     writeModuleDecl(c, d);
00124 
00125     // imports
00126     writeModuleImports(c, d);
00127 
00128     // write the opening declaration for the class incl any documentation,
00129     // interfaces and/or inheritence issues we have
00130     writeClassDecl(c, d);
00131 
00132     // start body of class
00133     d << " {" << m_endl;
00134 
00135 
00136     // Preparations
00137     //
00138 
00139     // sort attributes by Scope
00140     UMLAttributeList  atl;
00141     UMLAttributeList  atpub, atprot, atpriv, atpkg, atexport;
00142     UMLAttributeList  final_atpub, final_atprot, final_atpriv, final_atpkg, final_atexport;
00143 
00144     atpub.setAutoDelete(false);
00145     final_atpub.setAutoDelete(false);
00146     atprot.setAutoDelete(false);
00147     final_atprot.setAutoDelete(false);
00148     atpriv.setAutoDelete(false);
00149     final_atpriv.setAutoDelete(false);
00150     atpkg.setAutoDelete(false);
00151     final_atpkg.setAutoDelete(false);
00152     atexport.setAutoDelete(false);
00153     final_atexport.setAutoDelete(false);
00154 
00155     if (!isInterface) {
00156         UMLAttributeList atl = c->getAttributeList();
00157         for (UMLAttribute *at = atl.first(); at ; at = atl.next()) {
00158             switch(at->getVisibility())
00159             {
00160                 case Uml::Visibility::Public:
00161                     if(at->getStatic())
00162                         final_atpub.append(at);
00163                     else
00164                         atpub.append(at);
00165                     break;
00166                 case Uml::Visibility::Protected:
00167                     if(at->getStatic())
00168                         final_atprot.append(at);
00169                     else
00170                         atprot.append(at);
00171                     break;
00172                 case Uml::Visibility::Private:
00173                     if(at->getStatic())
00174                         final_atpriv.append(at);
00175                     else
00176                         atpriv.append(at);
00177                     break;/* TODO: requires support from the gui & other structures
00178                 case Uml::Visibility::Package:
00179                     if(at->getStatic())
00180                     final_atpkg.append(at);
00181                     else
00182                     atpkg.append(at);
00183                     break;
00184                 case Uml::Visibility::Export:
00185                     if(at->getStatic())
00186                     final_atexport.append(at);
00187                     else
00188                     atexport.append(at);
00189                     break;*/
00190                 default:
00191                     break;
00192             }
00193         }
00194     }
00195 
00196     // another preparation, determine what we have
00197     UMLAssociationList associations = c->getSpecificAssocs(Uml::at_Association); // BAD! only way to get "general" associations.
00198     UMLAssociationList uniAssociations = c->getUniAssociationToBeImplemented();
00199 
00200     UMLAssociationList aggregations = c->getAggregations();
00201     UMLAssociationList compositions = c->getCompositions();
00202 
00203     bool hasAssociations = aggregations.count() + associations.count() + compositions.count() + uniAssociations.count() > 0;
00204     bool hasAttributes = atl.count() > 0;
00205     bool hasAccessorMethods = hasAttributes || hasAssociations;
00206     bool hasOperationMethods = c->getOpList().count() > 0;
00207 
00208     // ATTRIBUTES
00209     //
00210 
00211     // write comment for section IF needed
00212     if (forceDoc() || hasAccessorMethods)
00213     {
00214         writeComment("", m_indentation, d);
00215         writeComment("Fields", m_indentation, d);
00216         writeComment("", m_indentation, d);
00217         writeBlankLine(d);
00218     }
00219 
00220     writeAttributeDecls(final_atpub, final_atprot, final_atpriv, d);
00221     writeAttributeDecls(atpub, atprot, atpriv, d);
00222 
00223     writeAssociationDecls(associations, c->getID(), d);
00224     writeAssociationDecls(uniAssociations, c->getID(), d);
00225     writeAssociationDecls(aggregations, c->getID(), d);
00226     writeAssociationDecls(compositions, c->getID(), d);
00227 
00228     //FIXME: find constructors and write them here
00229 
00230     // write constructors
00231     if(!isInterface) writeConstructor(c, d);
00232 
00233 
00234     // METHODS
00235     //
00236 
00237     // write comment for sub-section IF needed
00238     if (forceDoc() || hasAccessorMethods ) {
00239         writeComment("", m_indentation, d);
00240         writeComment("Accessors", m_indentation, d);
00241         writeComment("", m_indentation, d);
00242         writeBlankLine(d);
00243     }
00244 
00245 
00246     // Accessors for attributes
00247     writeAttributeMethods(final_atpub, Uml::Visibility::Public, d);
00248     writeAttributeMethods(final_atprot, Uml::Visibility::Protected, d);
00249     writeAttributeMethods(final_atpriv, Uml::Visibility::Private, d);
00250     writeAttributeMethods(atpub, Uml::Visibility::Public, d);
00251     writeAttributeMethods(atprot, Uml::Visibility::Protected, d);
00252     writeAttributeMethods(atpriv, Uml::Visibility::Private, d);
00253 
00254     // accessor methods for associations
00255 
00256     // first: determine the name of the other class
00257     writeAssociationMethods(associations, c, d);
00258     writeAssociationMethods(uniAssociations, c, d);
00259     writeAssociationMethods(aggregations, c, d);
00260     writeAssociationMethods(compositions, c, d);
00261 
00262     // Other operation methods
00263     // all other operations are now written
00264 
00265     // write comment for sub-section IF needed
00266     if (forceDoc() || hasOperationMethods) {
00267         writeComment("", m_indentation, d);
00268         writeComment("Other methods", m_indentation, d);
00269         writeComment("", m_indentation, d);
00270         writeBlankLine(d);
00271     }
00272 
00273     writeOperations(c, d);
00274 
00275     d << "}" << m_endl; // end class
00276 
00277     file.close();
00278     emit codeGenerated(c, true);
00279 }
00280 
00281 void DWriter::writeClassDecl(UMLClassifier *c, QTextStream &d) {
00282 
00283     // class documentation
00284     if (!c->getDoc().isEmpty()) {
00285         writeDocumentation("", c->getDoc(), "", "", d);
00286     }
00287 
00288     /*
00289      * Class declaration
00290      *
00291      * (private) class foo(T, ..., Z) : class1, ..., classN, interface1, ..., interfaceN
00292      *     a       b    c      d      e          f                        g
00293      */
00294 
00295     // (a) visibility modifier
00296     switch(c->getVisibility()) {
00297         case Uml::Visibility::Private: d << "private "; break;
00298         default: break;
00299     }
00300 
00301     // (b) keyword
00302     // TODO what about structs?
00303     if (isInterface) {
00304         d << "interface ";
00305     } else {
00306         if (c->getAbstract()) {
00307             d << "abstract ";
00308         }
00309 
00310         d << "class ";
00311     }
00312 
00313     // (c) class name
00314     QString classname = cleanName(c->getName()); // our class name
00315     d << classname;
00316 
00317     // (d) template parameters
00318     UMLTemplateList template_params = c->getTemplateList();
00319     if (template_params.count()) {
00320         d << "(";
00321 
00322         for (UMLTemplate *t = template_params.first(); t; ) {
00323             // TODO: hm, leaving the type blank results in "class"
00324             // so we omit it (also because "class" in this context is illegal)
00325             if (t->getTypeName() != "class") {
00326                 d << t->getTypeName();
00327                 d << " ";
00328             }
00329 
00330             d << t->getName();
00331 
00332             if ((t = template_params.next()) != NULL)
00333                 d << ", ";
00334         }
00335 
00336         d << ")";
00337     }
00338 
00339     // (e) inheritances
00340     UMLClassifierList superclasses =
00341         c->findSuperClassConcepts(UMLClassifier::CLASS);
00342     UMLClassifierList superinterfaces =
00343         c->findSuperClassConcepts(UMLClassifier::INTERFACE);
00344 
00345     int count = superclasses.count() + superinterfaces.count();
00346 
00347     if (count > 0) {
00348         d << " : ";
00349 
00350         // (f) base classes
00351         for (UMLClassifier * concept= superclasses.first(); concept; concept = superclasses.next()) {
00352             d << cleanName(concept->getName());
00353 
00354             count--;
00355 
00356             if (count>0) d << ", ";
00357         }
00358 
00359         // (g) interfaces
00360         for (UMLClassifier * concept= superinterfaces.first(); concept; concept = superinterfaces.next()) {
00361             d << cleanName(concept->getName());
00362 
00363             count--;
00364 
00365             if (count>0) d << ", ";
00366         }
00367     }
00368 }
00369 
00370 void DWriter::writeProtectionMod(Uml::Visibility visibility, QTextStream &d) {
00371     d << m_indentation << scopeToDDecl(visibility) << ":" << m_endl << m_endl;
00372 }
00373 
00374 void DWriter::writeAttributeDecl(Uml::Visibility visibility, UMLAttributeList &atlist, QTextStream &d) {
00375     if (atlist.count()==0) return;
00376 
00377     writeProtectionMod(visibility, d);
00378 
00379     for(UMLAttribute *at=atlist.first(); at; at=atlist.next()) {
00380         // documentation
00381         if (!at->getDoc().isEmpty()) {
00382             writeComment(at->getDoc(), m_indentation, d, true);
00383         }
00384 
00385         d << m_indentation;
00386 
00387         // static attribute?
00388         if (at->getStatic()) d << "static ";
00389 
00390         // method return type
00391         d << fixTypeName(at->getTypeName()) << " ";
00392 
00393         // TODO: find out whether this class has accessors or not
00394         bool hasAccessorMethods = true;
00395 
00396         // attribute name
00397         if (hasAccessorMethods) {
00398             d << "m_";
00399         }
00400         d << cleanName(at->getName());
00401 
00402         // initial value
00403         QString initVal = fixInitialStringDeclValue(at->getInitialValue(), at->getTypeName());
00404         if (!initVal.isEmpty()) d << " = " << initVal;
00405         d << ";" << m_endl << m_endl;
00406     }
00407 }
00408 
00409 void DWriter::writeAttributeDecls(UMLAttributeList &atpub, UMLAttributeList &atprot,
00410                                      UMLAttributeList &atpriv, QTextStream &d ) {
00411 
00412     writeAttributeDecl(Uml::Visibility::Public, atpub, d);
00413     writeAttributeDecl(Uml::Visibility::Protected, atprot, d);
00414     writeAttributeDecl(Uml::Visibility::Private, atpriv, d);
00415     //TODO: export and package
00416 }
00417 
00418 void DWriter::writeAttributeMethods(UMLAttributeList &atpub, Uml::Visibility visibility, QTextStream &d) {
00419     if (atpub.count()==0) return;
00420 
00421     writeProtectionMod(visibility, d);
00422 
00423     for(UMLAttribute *at=atpub.first(); at; at=atpub.next()) {
00424         QString fieldName = cleanName(at->getName());
00425         writeSingleAttributeAccessorMethods(
00426             at->getTypeName(), "m_" + fieldName, fieldName, at->getDoc(),
00427             visibility, Uml::chg_Changeable, at->getStatic(), d);
00428     }
00429 }
00430 
00431 void DWriter::writeComment(const QString &comment, const QString &myIndent,
00432                            QTextStream &d, bool dDocStyle) {
00433     if(dDocStyle) {
00434         d << myIndent << "" << m_endl;
00460     }
00461 }
00462 
00463 void DWriter::writeDocumentation(QString header, QString body, QString end, QString indent, QTextStream &d) {
00464     d << indent << "" << m_endl;
00476 }
00477 
00478 void DWriter::writeAssociationDecls(UMLAssociationList associations, Uml::IDType id, QTextStream &d) {
00479 
00480     if( forceSections() || !associations.isEmpty() )
00481     {
00482         bool printRoleA = false, printRoleB = false;
00483         for(UMLAssociation *a = associations.first(); a; a = associations.next())
00484         {
00485             // it may seem counter intuitive, but you want to insert the role of the
00486             // *other* class into *this* class.
00487             if (a->getObjectId(Uml::A) == id)
00488                 printRoleB = true;
00489 
00490             if (a->getObjectId(Uml::B) == id)
00491                 printRoleA = true;
00492 
00493             // First: we insert documentaion for association IF it has either role AND some documentation (!)
00494             if ((printRoleA || printRoleB) && !(a->getDoc().isEmpty()))
00495                 writeComment(a->getDoc(), m_indentation, d);
00496 
00497             // print RoleB decl
00498             if (printRoleB)
00499             {
00500                 QString fieldClassName = cleanName(getUMLObjectName(a->getObject(Uml::B)));
00501                 writeAssociationRoleDecl(fieldClassName, a->getRoleName(Uml::B), a->getMulti(Uml::B), a->getRoleDoc(Uml::B), a->getVisibility(Uml::B), d);
00502             }
00503 
00504             // print RoleA decl
00505             if (printRoleA)
00506             {
00507                 QString fieldClassName = cleanName(getUMLObjectName(a->getObject(Uml::A)));
00508                 writeAssociationRoleDecl(fieldClassName, a->getRoleName(Uml::A), a->getMulti(Uml::A), a->getRoleDoc(Uml::A), a->getVisibility(Uml::A), d);
00509             }
00510         }
00511     }
00512 }
00513 
00514 void DWriter::writeAssociationRoleDecl(QString fieldClassName,
00515         QString roleName, QString multi,
00516         QString doc, Uml::Visibility /* visib */, QTextStream &d) {
00517     // ONLY write out IF there is a rolename given
00518     // otherwise its not meant to be declared in the code
00519     if (roleName.isEmpty()) return;
00520 
00521     if (!doc.isEmpty()) {
00522         writeComment(doc, m_indentation, d);
00523     }
00524 
00525     bool hasAccessors = true;
00526 
00527     // declare the association based on whether it is this a single variable
00528     // or a List (Vector). One day this will be done correctly with special
00529     // multiplicity object that we don't have to figure out what it means via regex.
00530     if(multi.isEmpty() || multi.contains(QRegExp("^[01]$"))) {
00531         d << m_indentation << fieldClassName << " ";
00532 
00533         if (hasAccessors) d << "m_";
00534 
00535         d << deCapitaliseFirstLetter(roleName) << ";";
00536     } else {
00537         d << m_indentation << fieldClassName << "[] ";
00538         //TODO: templated containers
00539 
00540         if (hasAccessors) d << "m_";
00541 
00542         d << pluralize(deCapitaliseFirstLetter(roleName)) << ";";
00543         // from here we could initialize default values, or put in an init() section
00544         // of the constructors
00545     }
00546 
00547     // always put space between this and following decl, if any
00548     writeBlankLine(d);
00549 }
00550 
00551 void DWriter::writeAssociationMethods (UMLAssociationList associations, UMLClassifier *thisClass, QTextStream &d) {
00552     if( forceSections() || !associations.isEmpty() ) {
00553         for(UMLAssociation *a = associations.first(); a; a = associations.next()) {
00554             // insert the methods to access the role of the other
00555             // class in the code of this one
00556             if (a->getObjectId(Uml::A) == thisClass->getID()) {
00557                 // only write out IF there is a rolename given
00558                 if(!a->getRoleName(Uml::B).isEmpty()) {
00559                     QString fieldClassName = getUMLObjectName(a->getObject(Uml::B));
00560                     writeAssociationRoleMethod(fieldClassName,
00561                                                a->getRoleName(Uml::B),
00562                                                a->getMulti(Uml::B), a->getRoleDoc(Uml::B),
00563                                                a->getVisibility(Uml::B),
00564                                                a->getChangeability(Uml::B), d);
00565                 }
00566             }
00567 
00568             if (a->getObjectId(Uml::B) == thisClass->getID()) {
00569                 // only write out IF there is a rolename given
00570                 if(!a->getRoleName(Uml::A).isEmpty()) {
00571                     QString fieldClassName = getUMLObjectName(a->getObject(Uml::A));
00572                     writeAssociationRoleMethod(fieldClassName, a->getRoleName(Uml::A),
00573                                                a->getMulti(Uml::A),
00574                                                a->getRoleDoc(Uml::A),
00575                                                a->getVisibility(Uml::A),
00576                                                a->getChangeability(Uml::A),
00577                                                d);
00578                 }
00579             }
00580         }
00581     }
00582 }
00583 
00584 void DWriter::writeAssociationRoleMethod (QString fieldClassName, QString roleName, QString multi,
00585         QString description, Uml::Visibility visib, Uml::Changeability_Type change,
00586         QTextStream &d) {
00587     if(multi.isEmpty() || multi.contains(QRegExp("^[01]$"))) {
00588         QString fieldVarName = "m_" + deCapitaliseFirstLetter(roleName);
00589 
00590         writeSingleAttributeAccessorMethods(
00591             fieldClassName, fieldVarName, roleName, description, visib, change, false, d);
00592     } else {
00593         QString fieldVarName = "m_" + pluralize(deCapitaliseFirstLetter(roleName));
00594 
00595         writeVectorAttributeAccessorMethods(
00596             fieldClassName, fieldVarName, pluralize(roleName), description, visib, change, d);
00597     }
00598 }
00599 
00600 void DWriter::writeVectorAttributeAccessorMethods (QString fieldClassName, QString fieldVarName,
00601         QString fieldName, QString description,
00602         Uml::Visibility /* visibility */, Uml::Changeability_Type changeType,
00603         QTextStream &d) {
00604 
00605     fieldClassName = fixTypeName(fieldClassName);
00606     QString fieldNameUP = unPluralize(fieldName);
00607     QString fieldNameUC = capitaliseFirstLetter(fieldNameUP);
00608 
00609     // ONLY IF changeability is NOT Frozen
00610     if (changeType != Uml::chg_Frozen) {
00611         writeDocumentation("Adds a " + fieldNameUP + " to the list of " +
00612                            fieldName + ".", description, "", m_indentation, d);
00613 
00614         d << m_indentation << "void add" << fieldNameUC << "(";
00615         d << fieldClassName << " new" << fieldNameUC << ") {";
00616         d << startline << m_indentation << fieldVarName << " ~= new" << fieldNameUC << ";";
00617         d << startline << "}" << m_endl << m_endl;
00618     }
00619 
00620     // ONLY IF changeability is Changeable
00621     if (changeType == Uml::chg_Changeable) {
00622         writeDocumentation("Removes a " + fieldNameUP + " from the list of " +
00623                            fieldName + ".", description, "", m_indentation, d);
00624 
00625         d << m_indentation << "void remove" << fieldNameUC << "(";
00626         d << fieldClassName << " " << fieldNameUP << ") {" << startline;
00627         d << m_indentation << "int idx = " << fieldVarName << ".length;" << startline;
00628         d << m_indentation << "foreach(i, o; " << fieldVarName << ")" << startline;
00629         d << m_indentation << m_indentation << "if (o && o == " << fieldNameUP << ") {" << startline;
00630         d << m_indentation << m_indentation << m_indentation << "idx = i;" << startline;
00631         d << m_indentation << m_indentation << m_indentation << "break;" << startline;
00632         d << m_indentation << m_indentation << "}" << m_endl << startline;
00633         d << m_indentation << fieldVarName << " = " << fieldVarName;
00634         d << "[0..idx] ~ " << fieldVarName << "[idx..$];" << startline;
00635         d << "}" << m_endl << m_endl;
00636     }
00637 
00638     // always allow getting the list of stuff
00639     writeDocumentation("Returns the list of " + fieldName + ".",
00640                        description, "@return List of "+fieldName + ".",
00641                        m_indentation, d);
00642 
00643     d << m_indentation << fieldClassName << "[] get" << fieldName << "() {";
00644     d << startline << m_indentation << "return " << fieldVarName << ";";
00645     d << startline << "}" << m_endl << m_endl;
00646 }
00647 
00648 
00649 void DWriter::writeSingleAttributeAccessorMethods(QString fieldClassName,
00650      QString fieldVarName, QString fieldName, QString description, Uml::Visibility /* visibility */,
00651      Uml::Changeability_Type change, bool isFinal, QTextStream &d) {
00652 
00653     fieldClassName = fixTypeName(fieldClassName);
00654     QString fieldNameUC = capitaliseFirstLetter(fieldName);
00655     if (fieldName.left(2) == "m_") fieldName = fieldName.right(fieldName.length()-2);
00656 
00657     // set method
00658     if (change == Uml::chg_Changeable && !isFinal) {
00659         writeDocumentation("Sets the value of " + fieldName + ".", description,
00660                            "@param new" + fieldNameUC + " The new value of " + fieldName + ".",
00661                            m_indentation, d);
00662 
00663         d << m_indentation << fieldClassName << " " << fieldName << "(";
00664         d << fieldClassName << " new" << fieldNameUC << ") {";
00665         d << startline << m_indentation << "return " << fieldVarName << " = new" << fieldNameUC << ";";
00666         d << startline << "}" << m_endl << m_endl;
00667     }
00668 
00669     // get method
00670     writeDocumentation("Returns the value of " + fieldName + ".", description,
00671                        "@return The value of " + fieldName + ".",
00672                        m_indentation, d);
00673 
00674     d << m_indentation << fieldClassName << " " << fieldName << "() {";
00675     d << startline << m_indentation << "return " << fieldVarName << ";";
00676     d << startline << "}" << m_endl << m_endl;
00677 }
00678 
00679 void DWriter::writeConstructor(UMLClassifier *c, QTextStream &d) {
00680 
00681     if (forceDoc())
00682     {
00683         d<<startline;
00684         writeComment("", m_indentation, d);
00685         writeComment("Constructors", m_indentation, d);
00686         writeComment("", m_indentation, d);
00687         writeBlankLine(d);
00688     }
00689 
00690     // write the first constructor
00691     QString className = cleanName(c->getName());
00692     d << m_indentation << "public this("<<") { }";
00693 
00694 }
00695 
00696 // IF the type is "string" we need to declare it as
00697 // the D Object "String" (there is no string primative in D).
00698 // Same thing again for "bool" to "boolean"
00699 QString DWriter::fixTypeName(const QString& string) {
00700     if (string.isEmpty())
00701         return "void";
00702     if (string == "string")
00703         return "char[]";
00704     if (string == "unsigned short")
00705         return "ushort";
00706     if (string == "unsigned int")
00707         return "uint";
00708     if (string == "unsigned long")
00709         return "ulong";
00710     return string;
00711 }
00712 
00713 QStringList DWriter::defaultDatatypes() {
00714     QStringList l;
00715     l << "void"
00716     << "bool"
00717     << "byte"
00718     << "ubyte"
00719     << "short"
00720     << "ushort"
00721     << "int"
00722     << "uint"
00723     << "long"
00724     << "ulong"
00725     << "cent"
00726     << "ucent"
00727     << "float"
00728     << "double"
00729     << "real"
00730     << "ifloat"
00731     << "idouble"
00732     << "ireal"
00733     << "cfloat"
00734     << "cdouble"
00735     << "creal"
00736     << "char"
00737     << "wchar"
00738     << "dchar";
00739     return l;
00740 }
00741 
00742 
00743 bool DWriter::compareDMethod(UMLOperation *op1, UMLOperation *op2) {
00744     if (op1 == NULL || op2 == NULL)
00745         return false;
00746     if (op1 == op2)
00747         return true;
00748     if (op1->getName() != op2->getName())
00749         return false;
00750     UMLAttributeList atl1 = op1->getParmList();
00751     UMLAttributeList atl2 = op2->getParmList();
00752     if (atl1.count() != atl2.count())
00753         return false;
00754     UMLAttribute *at1;
00755     UMLAttribute *at2;
00756     for (at1  = atl1.first(), at2 = atl2.first(); at1 && at2 ; at1 = atl1.next(),at2 = atl2.next())
00757     {
00758         if (at1->getTypeName() != at2->getTypeName())
00759             return false;
00760     }
00761     return true;
00762 
00763 }
00764 
00765 bool DWriter::dMethodInList(UMLOperation *umlOp, UMLOperationList &opl) {
00766     for (UMLOperation *op = opl.first(); op; op = opl.next()) {
00767         if (DWriter::compareDMethod(op, umlOp)) {
00768             return true;
00769         }
00770     }
00771     return false;
00772 }
00773 
00774 void DWriter::getSuperImplementedOperations(UMLClassifier *c, UMLOperationList &yetImplementedOpList ,UMLOperationList &toBeImplementedOpList, bool noClassInPath) {
00775     UMLClassifierList superClasses = c->findSuperClassConcepts();
00776 
00777     for (UMLClassifier *concept= superClasses.first(); concept; concept = superClasses.next())
00778     {
00779         getSuperImplementedOperations(concept, yetImplementedOpList, toBeImplementedOpList, (concept->isInterface() && noClassInPath));
00780         UMLOperationList opl = concept->getOpList();
00781         for (UMLOperation *op = opl.first(); op; op = opl.next()) {
00782             if (concept->isInterface() && noClassInPath) {
00783                 if (!DWriter::dMethodInList(op,toBeImplementedOpList))
00784                     toBeImplementedOpList.append(op);
00785             }
00786             else
00787             {
00788                 if (!DWriter::dMethodInList(op, yetImplementedOpList))
00789                     yetImplementedOpList.append(op);
00790             }
00791         }
00792     }
00793 
00794 }
00795 
00796 void DWriter::getInterfacesOperationsToBeImplemented(UMLClassifier *c, UMLOperationList &opList ) {
00797     UMLOperationList yetImplementedOpList;
00798     UMLOperationList toBeImplementedOpList;
00799 
00800     getSuperImplementedOperations(c,yetImplementedOpList, toBeImplementedOpList);
00801     for (UMLOperation *op = toBeImplementedOpList.first(); op; op = toBeImplementedOpList.next())
00802     {
00803         if ( ! DWriter::dMethodInList(op, yetImplementedOpList) && ! DWriter::dMethodInList(op, opList) )
00804             opList.append(op);
00805     }
00806 }
00807 
00808 void DWriter::writeOperations(UMLClassifier *c, QTextStream &d) {
00809     UMLOperationList opl;
00810     UMLOperationList oppub,opprot,oppriv;
00811     oppub.setAutoDelete(false);
00812     opprot.setAutoDelete(false);
00813     oppriv.setAutoDelete(false);
00814 
00815     //sort operations by scope first and see if there are abstract methods
00816     opl = c->getOpList();
00817     if (! c->isInterface()) {
00818         getInterfacesOperationsToBeImplemented(c, opl);
00819     }
00820     for (UMLOperation *op = opl.first(); op; op = opl.next()) {
00821         switch(op->getVisibility()) {
00822           case Uml::Visibility::Public:
00823             oppub.append(op);
00824             break;
00825           case Uml::Visibility::Protected:
00826             opprot.append(op);
00827             break;
00828           case Uml::Visibility::Private:
00829             oppriv.append(op);
00830             break;
00831           default: //TODO: package, export
00832             break;
00833         }
00834     }
00835 
00836     // do people REALLY want these comments? Hmm.
00837     /*
00838       if(forceSections() || oppub.count())
00839       {
00840       writeComment("public operations",m_indentation,d);
00841         writeBlankLine(d);
00842       }
00843     */
00844 
00845     if (oppub.count() > 0) {
00846         writeProtectionMod(Uml::Visibility::Public, d);
00847 
00848         writeOperations(oppub,d);
00849     }
00850 
00851     if (opprot.count() > 0) {
00852         writeProtectionMod(Uml::Visibility::Protected, d);
00853 
00854         writeOperations(opprot, d);
00855     }
00856 
00857     if (oppriv.count() > 0) {
00858         writeProtectionMod(Uml::Visibility::Private, d);
00859 
00860         writeOperations(oppriv, d);
00861     }
00862 
00863 }
00864 
00865 void DWriter::writeOperations(UMLOperationList &oplist, QTextStream &d) {
00866     UMLAttributeList atl;
00867     QString str;
00868 
00869     // generate method decl for each operation given
00870     for(UMLOperation *op=oplist.first(); op; op=oplist.next()) {
00871         QString returnStr = "";
00872         // write documentation
00873 
00874         QString methodReturnType = fixTypeName(op->getTypeName());
00875 
00876         //TODO: return type comment
00877         if(methodReturnType != "void") {
00878             returnStr += "@return " + methodReturnType + m_endl;
00879         }
00880 
00881         str = ""; // reset for next method
00882         if (op->getAbstract() && !isInterface) str += "abstract ";
00883         if (op->getStatic()) str += "static ";
00884 
00885         str += methodReturnType + ' ' +cleanName(op->getName()) + "(";
00886 
00887         atl = op->getParmList();
00888         int i = atl.count();
00889         int j = 0;
00890         for (UMLAttribute *at = atl.first(); at; at = atl.next(), j++) {
00891             QString typeName = fixTypeName(at->getTypeName());
00892             QString atName = cleanName(at->getName());
00893             str += typeName + ' ' + atName +
00894                    (!(at->getInitialValue().isEmpty()) ?
00895                     (QString(" = ")+at->getInitialValue()) :
00896                     QString(""))
00897                    + ((j < i-1)?", ":"");
00898             returnStr += "@param " + atName+' '+at->getDoc() + m_endl;
00899         }
00900 
00901         str+= ")";
00902 
00903         // method only gets a body IF its not abstract
00904         if (op->getAbstract() || isInterface)
00905             str += ";"; // terminate now
00906         else
00907             str += startline + "{" + startline + "}"; // empty method body
00908 
00909         // write it out
00910         writeDocumentation("", op->getDoc(), returnStr, m_indentation, d);
00911         d << m_indentation << str << m_endl << m_endl;
00912     }
00913 }
00914 
00915 QString DWriter::fixInitialStringDeclValue(QString value, QString type) {
00916     // check for strings only
00917     if (!value.isEmpty() && type == "String") {
00918         if (!value.startsWith("\""))
00919             value.prepend("\"");
00920         if (!value.endsWith("\""))
00921             value.append("\"");
00922     }
00923     return value;
00924 }
00925 
00926 QString DWriter::scopeToDDecl(Uml::Visibility scope) {
00927     QString scopeString;
00928 
00929     switch(scope) {
00930         case Uml::Visibility::Public: scopeString = "public"; break;
00931         case Uml::Visibility::Protected: scopeString = "protected"; break;
00932         case Uml::Visibility::Private: scopeString = "private"; break;
00933         default: break; //TODO: package and export
00934     }
00935 
00936     return scopeString;
00937 }
00938 
00939 // methods like this _shouldn't_ be needed IF we properly did things thruought the code.
00940 QString DWriter::getUMLObjectName(UMLObject *obj) {
00941     return(obj!=0)?obj->getName():QString("NULL");
00942 }
00943 
00944 QString DWriter::capitaliseFirstLetter(QString string) {
00945     string.replace( 0, 1, string[0].upper());
00946     return string;
00947 }
00948 
00949 QString DWriter::deCapitaliseFirstLetter(QString string) {
00950     string.replace( 0, 1, string[0].lower());
00951     return string;
00952 }
00953 
00954 QString DWriter::pluralize(QString string) {
00955     return string + (string.right(1) == "s" ? "es" : "s");
00956 }
00957 
00958 QString DWriter::unPluralize(QString string) {
00959     // does not handle special cases liek datum -> data, etc.
00960 
00961     if (string.length() > 2 && string.right(3) == "ses") {
00962         return string.left(string.length() - 2);
00963     }
00964 
00965     if (string.right(1) == "s") {
00966         return string.left(string.length() - 1);
00967     }
00968 
00969     return string;
00970 }
00971 
00972 void DWriter::writeBlankLine(QTextStream &d) {
00973     d << m_endl;
00974 }
00975 
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