umbrello API Documentation

javaclassifiercodedocument.cpp

00001 /***************************************************************************
00002  *                                                                         *
00003  *   This program is free software; you can redistribute it and/or modify  *
00004  *   it under the terms of the GNU General Public License as published by  *
00005  *   the Free Software Foundation; either version 2 of the License, or     *
00006  *   (at your option) any later version.                                   *
00007  *                                                                         *
00008  *   copyright (C) 2004-2007                                               *
00009  *   Umbrello UML Modeller Authors <uml-devel@uml.sf.net>                  *
00010  ***************************************************************************/
00011 
00012 /*  This code generated by:
00013  *      Author : thomas
00014  *      Date   : Mon Jun 23 2003
00015  */
00016 
00027 // own header
00028 #include "javaclassifiercodedocument.h"
00029 
00030 // qt/kde includes
00031 #include <kdebug.h>
00032 #include <qregexp.h>
00033 
00034 // local includes
00035 #include "javacodegenerator.h"
00036 #include "javacodecomment.h"
00037 #include "javaclassdeclarationblock.h"
00038 #include "javacodeclassfielddeclarationblock.h"
00039 #include "../classifier.h"
00040 #include "../codegenerationpolicy.h"
00041 #include "../uml.h"
00042 
00043 // Constructors/Destructors
00044 //
00045 
00046 JavaClassifierCodeDocument::JavaClassifierCodeDocument ( UMLClassifier * concept )
00047         : ClassifierCodeDocument (concept) {
00048     init();
00049 }
00050 
00051 JavaClassifierCodeDocument::~JavaClassifierCodeDocument ( ) { }
00052 
00053 //
00054 // Methods
00055 //
00056 
00057 // Accessor methods
00058 //
00059 
00060 // Make it easier on ourselves
00061 JavaCodeGenerationPolicy * JavaClassifierCodeDocument::getJavaPolicy() {
00062     CodeGenPolicyExt *pe = UMLApp::app()->getPolicyExt();
00063     JavaCodeGenerationPolicy * policy = dynamic_cast<JavaCodeGenerationPolicy*>(pe);
00064     return policy;
00065 }
00066 
00071 /*
00072 CodeDocumentDialog JavaClassifierCodeDocument::getDialog ( ) {
00073 
00074 }
00075 */
00076 
00077 bool JavaClassifierCodeDocument::forceDoc () {
00078     return UMLApp::app()->getCommonPolicy()->getCodeVerboseDocumentComments();
00079 }
00080 
00081 // We overwritten by Java language implementation to get lowercase path
00082 QString JavaClassifierCodeDocument::getPath ( )
00083 {
00084 
00085     QString path = getPackage();
00086 
00087     // Replace all white spaces with blanks
00088     path.simplifyWhiteSpace();
00089 
00090     // Replace all blanks with underscore
00091     path.replace(QRegExp(" "), "_");
00092 
00093     path.replace(QRegExp("\\."),"/");
00094     path.replace(QRegExp("::"), "/");
00095 
00096     path.lower();
00097 
00098     return path;
00099 
00100 }
00101 
00102 
00103 // Other methods
00104 //
00105 
00106 QString JavaClassifierCodeDocument::capitalizeFirstLetter(const QString &string)
00107 {
00108     return JavaCodeGenerator::capitalizeFirstLetter(string);
00109 }
00110 
00111 QString JavaClassifierCodeDocument::getJavaClassName (const QString &name) {
00112     return capitalizeFirstLetter(CodeGenerator::cleanName(name));
00113 }
00114 
00115 // Initialize this java classifier code document
00116 void JavaClassifierCodeDocument::init ( ) {
00117 
00118     setFileExtension(".java");
00119 
00120     //initCodeClassFields(); // this is dubious because it calls down to
00121                              // CodeGenFactory::newCodeClassField(this)
00122                              // but "this" is still in construction at that time.
00123 
00124     classDeclCodeBlock = 0;
00125     operationsBlock = 0;
00126     constructorBlock = 0;
00127 
00128     // this will call updateContent() as well as other things that sync our document.
00129     synchronize();
00130 }
00131 
00135 // in the vannilla version, we just tack all operations on the end
00136 // of the document
00137 bool JavaClassifierCodeDocument::addCodeOperation (CodeOperation * op ) {
00138 
00139     if(!op->getParentOperation()->isLifeOperation())
00140         return operationsBlock->addTextBlock(op);
00141     else
00142         return constructorBlock->addTextBlock(op);
00143 }
00144 
00145 // Sigh. NOT optimal. The only reason that we need to have this
00146 // is so we can create the JavaClassDeclarationBlock.
00147 // would be better if we could create a handler interface that each
00148 // codeblock used so all we have to do here is add the handler
00149 // for "javaclassdeclarationblock"
00150 void JavaClassifierCodeDocument::loadChildTextBlocksFromNode ( QDomElement & root)
00151 {
00152 
00153     QDomNode tnode = root.firstChild();
00154     QDomElement telement = tnode.toElement();
00155     bool loadCheckForChildrenOK = false;
00156     while( !telement.isNull() ) {
00157         QString nodeName = telement.tagName();
00158 
00159         if( nodeName == "textblocks" ) {
00160 
00161             QDomNode node = telement.firstChild();
00162             QDomElement element = node.toElement();
00163 
00164             // if there is nothing to begin with, then we don't worry about it
00165             loadCheckForChildrenOK = element.isNull() ? true : false;
00166 
00167             while( !element.isNull() ) {
00168                 QString name = element.tagName();
00169 
00170                 if( name == "codecomment" ) {
00171                     CodeComment * block = new JavaCodeComment(this);
00172                     block->loadFromXMI(element);
00173                     if(!addTextBlock(block))
00174                     {
00175                         kError()<<"loadFromXMI : unable to add codeComment to :"<<this<<endl;
00176                         block->deleteLater();
00177                     } else
00178                         loadCheckForChildrenOK= true;
00179                 } else
00180                     if( name == "codeaccessormethod" ||
00181                             name == "ccfdeclarationcodeblock"
00182                       ) {
00183                         QString acctag = element.attribute("tag","");
00184                         // search for our method in the
00185                         TextBlock * tb = findCodeClassFieldTextBlockByTag(acctag);
00186                         if(!tb || !addTextBlock(tb))
00187                         {
00188                             kError()<<"loadFromXMI : unable to add codeclassfield child method to:"<<this<<endl;
00189                             // DON'T delete
00190                         } else
00191                             loadCheckForChildrenOK= true;
00192 
00193                     } else
00194                         if( name == "codeblock" ) {
00195                             CodeBlock * block = newCodeBlock();
00196                             block->loadFromXMI(element);
00197                             if(!addTextBlock(block))
00198                             {
00199                                 kError()<<"loadFromXMI : unable to add codeBlock to :"<<this<<endl;
00200                                 block->deleteLater();
00201                             } else
00202                                 loadCheckForChildrenOK= true;
00203                         } else
00204                             if( name == "codeblockwithcomments" ) {
00205                                 CodeBlockWithComments * block = newCodeBlockWithComments();
00206                                 block->loadFromXMI(element);
00207                                 if(!addTextBlock(block))
00208                                 {
00209                                     kError()<<"loadFromXMI : unable to add codeBlockwithcomments to:"<<this<<endl;
00210                                     block->deleteLater();
00211                                 } else
00212                                     loadCheckForChildrenOK= true;
00213                             } else
00214                                 if( name == "header" ) {
00215                                     // do nothing.. this is treated elsewhere
00216                                 } else
00217                                     if( name == "hierarchicalcodeblock" ) {
00218                                         HierarchicalCodeBlock * block = newHierarchicalCodeBlock();
00219                                         block->loadFromXMI(element);
00220                                         if(!addTextBlock(block))
00221                                         {
00222                                             kError()<<"Unable to add hierarchicalcodeBlock to:"<<this<<endl;
00223                                             block->deleteLater();
00224                                         } else
00225                                             loadCheckForChildrenOK= true;
00226                                     } else
00227                                         if( name == "codeoperation" ) {
00228                                             // find the code operation by id
00229                                             QString id = element.attribute("parent_id","-1");
00230                                             UMLObject * obj = UMLApp::app()->getDocument()->findObjectById(STR2ID(id));
00231                                             UMLOperation * op = dynamic_cast<UMLOperation*>(obj);
00232                                             if(op) {
00233                                                 CodeOperation * block = new JavaCodeOperation(this, op);
00234                                                 block->loadFromXMI(element);
00235                                                 if(addTextBlock(block))
00236                                                     loadCheckForChildrenOK= true;
00237                                                 else
00238                                                 {
00239                                                     kError()<<"Unable to add codeoperation to:"<<this<<endl;
00240                                                     block->deleteLater();
00241                                                 }
00242                                             } else
00243                                                 kError()<<"Unable to find operation create codeoperation for:"<<this<<endl;
00244                                         } else
00245                                             if( name == "javaclassdeclarationblock" )
00246                                             {
00247                                                 JavaClassDeclarationBlock * block = getClassDecl();
00248                                                 block->loadFromXMI(element);
00249                                                 if(!addTextBlock(block))
00250                                                 {
00251                                                     kError()<<"Unable to add java code declaration block to:"<<this<<endl;
00252                                                     // DON'T delete.
00253                                                     // block->deleteLater();
00254                                                 } else
00255                                                     loadCheckForChildrenOK= true;
00256                                             }
00257                 // This last item is only needed for extreme debugging conditions
00258                 // (E.g. making new codeclassdocument loader)
00259                 // else
00260                 //        kDebug()<<" LoadFromXMI: Got strange tag in text block stack:"<<name<<", ignorning"<<endl;
00261 
00262                 node = element.nextSibling();
00263                 element = node.toElement();
00264             }
00265             break;
00266         }
00267 
00268         tnode = telement.nextSibling();
00269         telement = tnode.toElement();
00270     }
00271 
00272     if(!loadCheckForChildrenOK)
00273     {
00274         CodeDocument * test = dynamic_cast<CodeDocument*>(this);
00275         if(test)
00276         {
00277             kWarning()<<" loadChildBlocks : unable to initialize any child blocks in doc: "<<test->getFileName()<<" "<<this<<endl;
00278         } else {
00279             HierarchicalCodeBlock * hb = dynamic_cast<HierarchicalCodeBlock*>(this);
00280             if(hb)
00281                 kWarning()<<" loadChildBlocks : unable to initialize any child blocks in Hblock: "<<hb->getTag()<<" "<<this<<endl;
00282             else
00283                 kDebug()<<" loadChildBlocks : unable to initialize any child blocks in UNKNOWN OBJ:"<<this<<endl;
00284         }
00285     }
00286 
00287 
00288 }
00289 
00290 QString JavaClassifierCodeDocument::scopeToJavaDecl(Uml::Visibility scope)
00291 {
00292     QString scopeString;
00293     switch(scope)
00294     {
00295       case Uml::Visibility::Public:
00296         scopeString = "public";
00297         break;
00298       case Uml::Visibility::Protected:
00299         scopeString = "protected";
00300         break;
00301       case Uml::Visibility::Private:
00302       case Uml::Visibility::Implementation:
00303           default:
00304         scopeString = "private";
00305         break;
00306     }
00307     return scopeString;
00308 }
00309 
00310 JavaClassDeclarationBlock * JavaClassifierCodeDocument::getClassDecl()
00311 {
00312     if(!classDeclCodeBlock)
00313     {
00314         classDeclCodeBlock = new JavaClassDeclarationBlock (this);
00315         classDeclCodeBlock->setTag("ClassDeclBlock");
00316     }
00317     return classDeclCodeBlock;
00318 }
00319 
00320 void JavaClassifierCodeDocument::resetTextBlocks()
00321 {
00322 
00323     // all special pointers to text blocks need to be zero'd out
00324     operationsBlock = 0;
00325     constructorBlock = 0;
00326     classDeclCodeBlock = 0;
00327 
00328     // now do traditional release of text blocks.
00329     ClassifierCodeDocument::resetTextBlocks();
00330 }
00331 
00332 // This method will cause the class to rebuild its text representation.
00333 // based on the parent classifier object.
00334 // For any situation in which this is called, we are either building the code
00335 // document up, or replacing/regenerating the existing auto-generated parts. As
00336 // such, we will want to insert everything we resonablely will want
00337 // during creation. We can set various parts of the document (esp. the
00338 // comments) to appear or not, as needed.
00339 void JavaClassifierCodeDocument::updateContent( )
00340 {
00341     // Gather info on the various fields and parent objects of this class...
00342     UMLClassifier * c = getParentClassifier();
00343     CodeGenerationPolicy * commonPolicy = UMLApp::app()->getCommonPolicy();
00344     CodeGenPolicyExt * pe = UMLApp::app()->getPolicyExt();
00345     JavaCodeGenerationPolicy * policy = dynamic_cast<JavaCodeGenerationPolicy*>(pe);
00346 
00347     // first, set the global flag on whether or not to show classfield info
00348     // This depends on whether or not we have attribute/association classes
00349     CodeClassFieldList * cfList = getCodeClassFieldList();
00350     for(CodeClassField * field = cfList->first(); field; field = cfList->next())
00351         if(field->parentIsAttribute())
00352             field->setWriteOutMethods(policy->getAutoGenerateAttribAccessors());
00353         else
00354             field->setWriteOutMethods(policy->getAutoGenerateAssocAccessors());
00355 
00356     // attribute-based ClassFields
00357     // we do it this way to have the static fields sorted out from regular ones
00358     CodeClassFieldList staticAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, true);
00359     CodeClassFieldList attribClassFields = getSpecificClassFields (CodeClassField::Attribute, false);
00360     // association-based ClassFields
00361     // don't care if they are static or not..all are lumped together
00362     CodeClassFieldList plainAssocClassFields = getSpecificClassFields ( CodeClassField::PlainAssociation );
00363     CodeClassFieldList aggregationClassFields = getSpecificClassFields ( CodeClassField::Aggregation );
00364     CodeClassFieldList compositionClassFields = getSpecificClassFields ( CodeClassField::Composition );
00365 
00366     bool isInterface = parentIsInterface();
00367     bool hasOperationMethods = c->getOpList().last() ? true : false;
00368     QString endLine = commonPolicy->getNewLineEndingChars(); // a shortcut..so we don't have to call this all the time
00369 
00370     //
00371     // START GENERATING CODE/TEXT BLOCKS and COMMENTS FOR THE DOCUMENT
00372     //
00373 
00374     //
00375     // PACKAGE CODE BLOCK
00376     //
00377     QString pkgs = getPackage();
00378     pkgs.replace(QRegExp("::"), ".");
00379     QString packageText = getPackage().isEmpty() ? "" : "package "+pkgs+';'+endLine;
00380     CodeBlockWithComments * pblock = addOrUpdateTaggedCodeBlockWithComments("packages", packageText, "", 0, false);
00381     if(packageText.isEmpty() && pblock->getContentType() == CodeBlock::AutoGenerated)
00382         pblock->setWriteOutText(false);
00383     else
00384         pblock->setWriteOutText(true);
00385 
00386     // IMPORT CODEBLOCK
00387     //
00388     // Q: Why all utils? Isnt just List and Vector the only classes we are using?
00389     // A: doesn't matter at all; its more readable to just include '*' and java compilers
00390     //    don't slow down or anything. (TZ)
00391     QString importStatement = "";
00392     if ( hasObjectVectorClassFields() )
00393         importStatement.append("import java.util.*;");
00394 
00395     //only import classes in a different package from this class
00396     UMLPackageList imports;
00397     QMap<UMLPackage*, QString> packageMap; // so we don't repeat packages
00398 
00399     CodeGenerator::findObjectsRelated(c,imports);
00400     for(UMLPackage *con = imports.first(); con ; con = imports.next())
00401         // NO (default) datatypes in the import statement.. use defined
00402         // ones whould be possible, but no idea how to do that...at least for now.
00403         // Dynamic casting is slow..not an optimal way to do this.
00404         if (!packageMap.contains(con) && con->getBaseType() != Uml::ot_Datatype)
00405         {
00406             packageMap.insert(con, con->getPackage());
00407 
00408             // now, we DON'T need to import classes that are already in our own package
00409             // (that is, IF a package is specified). Otherwise, we should have a declaration.
00410             if (con->getPackage() != c->getPackage() ||
00411                     (c->getPackage().isEmpty() && con->getPackage().isEmpty()))
00412             {
00413                 importStatement.append(endLine+"import ");
00414                 if(!con->getPackage().isEmpty())
00415                     importStatement.append(con->getPackage()+'.');
00416                 importStatement.append(CodeGenerator::cleanName(con->getName())+';');
00417             }
00418         }
00419     // now, add/update the imports codeblock
00420     CodeBlockWithComments * iblock = addOrUpdateTaggedCodeBlockWithComments("imports", importStatement, "", 0, false);
00421     if(importStatement.isEmpty() && iblock->getContentType() == CodeBlock::AutoGenerated)
00422         iblock->setWriteOutText(false);
00423     else
00424         iblock->setWriteOutText(true);
00425 
00426     // CLASS DECLARATION BLOCK
00427     //
00428 
00429     // get the declaration block. If its not already present, add it too
00430     JavaClassDeclarationBlock * myClassDeclCodeBlock = getClassDecl();
00431     addTextBlock(myClassDeclCodeBlock); // note: wont add if already present
00432 
00433     // NOW create document in sections..
00434     // now we want to populate the body of our class
00435     // our layout is the following general groupings of code blocks:
00436 
00437     // start java classifier document
00438 
00439     // header comment
00440 
00441     // package code block
00442 
00443     // import code block
00444 
00445     // class declaration
00446 
00447     //   section:
00448     //   - class field declaration section comment
00449     //   - class field declarations (0+ codeblocks)
00450 
00451     //   section:
00452     //   - methods section comment
00453 
00454     //     sub-section: constructor ops
00455     //     - constructor method section comment
00456     //     - constructor methods (0+ codeblocks)
00457 
00458     //     sub-section: accessors
00459     //     - accessor method section comment
00460     //     - static accessor methods (0+ codeblocks)
00461     //     - non-static accessor methods (0+ codeblocks)
00462 
00463     //     sub-section: non-constructor ops
00464     //     - operation method section comment
00465     //     - operations (0+ codeblocks)
00466 
00467     // end class declaration
00468 
00469     // end java classifier document
00470 
00471 
00472     // Q: Why use the more complicated scheme of arranging code blocks within codeblocks?
00473     // A: This will allow us later to preserve the format of our document so that if
00474     //    codeblocks are added, they may be easily added in the correct place, rather than at
00475     //    the end of the document, or by using a difficult algorithm to find the location of
00476     //    the last appropriate code block sibling (which may not exist.. for example user adds
00477     //    a constructor operation, but there currently are no constructor code blocks
00478     //    within the document).
00479 
00480     //
00481     // * CLASS FIELD declaration section
00482     //
00483 
00484     // get/create the field declaration code block
00485     HierarchicalCodeBlock * fieldDeclBlock = myClassDeclCodeBlock->getHierarchicalCodeBlock("fieldsDecl", "Fields", 1);
00486 
00487     // Update the comment: we only set comment to appear under the following conditions
00488     CodeComment * fcomment = fieldDeclBlock->getComment();
00489     if (isInterface || (!forceDoc() && !hasClassFields()) )
00490         fcomment->setWriteOutText(false);
00491     else
00492         fcomment->setWriteOutText(true);
00493 
00494     // now actually declare the fields within the appropriate HCodeBlock
00495     declareClassFields(staticAttribClassFields, fieldDeclBlock);
00496     declareClassFields(attribClassFields, fieldDeclBlock);
00497     declareClassFields(plainAssocClassFields, fieldDeclBlock);
00498     declareClassFields(aggregationClassFields, fieldDeclBlock);
00499     declareClassFields(compositionClassFields, fieldDeclBlock);
00500 
00501     //
00502     // METHODS section
00503     //
00504 
00505     // get/create the method codeblock
00506     HierarchicalCodeBlock * methodsBlock = myClassDeclCodeBlock->getHierarchicalCodeBlock("methodsBlock", "Methods", 1);
00507 
00508     // Update the section comment
00509     CodeComment * methodsComment = methodsBlock->getComment();
00510     // set conditions for showing this comment
00511     if (!forceDoc() && !hasClassFields() && !hasOperationMethods)
00512         methodsComment->setWriteOutText(false);
00513     else
00514         methodsComment->setWriteOutText(true);
00515 
00516     // METHODS sub-section : constructor methods
00517     //
00518 
00519     // get/create the constructor codeblock
00520     HierarchicalCodeBlock * constBlock = methodsBlock->getHierarchicalCodeBlock("constructorMethods", "Constructors", 1);
00521     constructorBlock = constBlock; // record this codeblock for later, when operations are updated
00522 
00523     // special condiions for showing comment: only when autogenerateding empty constructors
00524     // Although, we *should* check for other constructor methods too
00525     CodeComment * constComment = constBlock->getComment();
00526     CodeGenerationPolicy *pol = UMLApp::app()->getCommonPolicy();
00527     if (!forceDoc() && (isInterface || !pol->getAutoGenerateConstructors()))
00528         constComment->setWriteOutText(false);
00529     else
00530         constComment->setWriteOutText(true);
00531 
00532     // add/get the empty constructor
00533     QString JavaClassName = getJavaClassName(c->getName());
00534     QString emptyConstStatement = "public "+JavaClassName+" ( ) { }";
00535     CodeBlockWithComments * emptyConstBlock =
00536         constBlock->addOrUpdateTaggedCodeBlockWithComments("emptyconstructor", emptyConstStatement, "Empty Constructor", 1, false);
00537     // Now, as an additional condition we only show the empty constructor block
00538     // IF it was desired to be shown
00539     if(parentIsClass() && pol->getAutoGenerateConstructors())
00540         emptyConstBlock->setWriteOutText(true);
00541     else
00542         emptyConstBlock->setWriteOutText(false);
00543 
00544     // METHODS subsection : ACCESSOR METHODS
00545     //
00546 
00547     // get/create the accessor codeblock
00548     HierarchicalCodeBlock * accessorBlock = methodsBlock->getHierarchicalCodeBlock("accessorMethods", "Accessor Methods", 1);
00549 
00550     // set conditions for showing section comment
00551     CodeComment * accessComment = accessorBlock->getComment();
00552     if (!forceDoc() && !hasClassFields())
00553         accessComment->setWriteOutText(false);
00554     else
00555         accessComment->setWriteOutText(true);
00556 
00557     // now, 2 sub-sub sections in accessor block
00558     // add/update accessor methods for attributes
00559     HierarchicalCodeBlock * staticAccessors = accessorBlock->getHierarchicalCodeBlock("staticAccessorMethods", "", 1);
00560     staticAccessors->getComment()->setWriteOutText(false); // never write block comment
00561     staticAccessors->addCodeClassFieldMethods(staticAttribClassFields);
00562     staticAccessors->addCodeClassFieldMethods(attribClassFields);
00563 
00564     // add/update accessor methods for associations
00565     HierarchicalCodeBlock * regularAccessors = accessorBlock->getHierarchicalCodeBlock("regularAccessorMethods", "", 1);
00566     regularAccessors->getComment()->setWriteOutText(false); // never write block comment
00567     regularAccessors->addCodeClassFieldMethods(plainAssocClassFields);
00568     regularAccessors->addCodeClassFieldMethods(aggregationClassFields);
00569     regularAccessors->addCodeClassFieldMethods(compositionClassFields);
00570 
00571     // METHODS subsection : Operation methods (which arent constructors)
00572     //
00573 
00574     // get/create the operations codeblock
00575     operationsBlock = methodsBlock->getHierarchicalCodeBlock("operationMethods", "Operations", 1);
00576 
00577     // set conditions for showing section comment
00578     CodeComment * ocomment = operationsBlock->getComment();
00579     if (!forceDoc() && !hasOperationMethods )
00580         ocomment->setWriteOutText(false);
00581     else
00582         ocomment->setWriteOutText(true);
00583 
00584 }
00585 
00586 
00587 #include "javaclassifiercodedocument.moc"
KDE Logo
This file is part of the documentation for umbrello Version 3.1.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Jun 26 08:07:57 2007 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003