/*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * copyright (C) 2004-2007 * * Umbrello UML Modeller Authors * ***************************************************************************/ /* This code generated by: * Author : thomas * Date : Mon Jun 23 2003 */ /** We carve the Java document up into sections as follows: * header * package declaration * import statements * class declaration * guts of the class (e.g. field decl, accessor methods, operations, dependant classes) */ // own header #include "javaclassifiercodedocument.h" // qt/kde includes #include #include // local includes #include "javacodegenerator.h" #include "javacodecomment.h" #include "javaclassdeclarationblock.h" #include "javacodeclassfielddeclarationblock.h" #include "codegen_utils.h" #include "../classifier.h" #include "../codegenerationpolicy.h" #include "../uml.h" // Constructors/Destructors // JavaClassifierCodeDocument::JavaClassifierCodeDocument ( UMLClassifier * concept ) : ClassifierCodeDocument (concept) { init(); } JavaClassifierCodeDocument::~JavaClassifierCodeDocument ( ) { } // // Methods // // Accessor methods // // Make it easier on ourselves JavaCodeGenerationPolicy * JavaClassifierCodeDocument::getJavaPolicy() { CodeGenPolicyExt *pe = UMLApp::app()->getPolicyExt(); JavaCodeGenerationPolicy * policy = dynamic_cast(pe); return policy; } /** * Get the dialog widget which allows user interaction with the object parameters. * @return CodeDocumentDialog */ /* CodeDocumentDialog JavaClassifierCodeDocument::getDialog ( ) { } */ bool JavaClassifierCodeDocument::forceDoc () { return UMLApp::app()->getCommonPolicy()->getCodeVerboseDocumentComments(); } // We overwritten by Java language implementation to get lowercase path TQString JavaClassifierCodeDocument::getPath ( ) { TQString path = getPackage(); // Replace all white spaces with blanks path.simplifyWhiteSpace(); // Replace all blanks with underscore path.replace(TQRegExp(" "), "_"); path.replace(TQRegExp("\\."),"/"); path.replace(TQRegExp("::"), "/"); path.lower(); return path; } // Other methods // TQString JavaClassifierCodeDocument::getJavaClassName (const TQString &name) { return Codegen_Utils::capitalizeFirstLetter(CodeGenerator::cleanName(name)); } // Initialize this java classifier code document void JavaClassifierCodeDocument::init ( ) { setFileExtension(".java"); //initCodeClassFields(); // this is dubious because it calls down to // CodeGenFactory::newCodeClassField(this) // but "this" is still in construction at that time. classDeclCodeBlock = 0; operationsBlock = 0; constructorBlock = 0; // this will call updateContent() as well as other things that sync our document. synchronize(); } /** * @param op */ // in the vannilla version, we just tack all operations on the end // of the document bool JavaClassifierCodeDocument::addCodeOperation (CodeOperation * op ) { if(!op->getParentOperation()->isLifeOperation()) return operationsBlock->addTextBlock(op); else return constructorBlock->addTextBlock(op); } // Sigh. NOT optimal. The only reason that we need to have this // is so we can create the JavaClassDeclarationBlock. // would be better if we could create a handler interface that each // codeblock used so all we have to do here is add the handler // for "javaclassdeclarationblock" void JavaClassifierCodeDocument::loadChildTextBlocksFromNode ( TQDomElement & root) { TQDomNode tnode = root.firstChild(); TQDomElement telement = tnode.toElement(); bool loadCheckForChildrenOK = false; while( !telement.isNull() ) { TQString nodeName = telement.tagName(); if( nodeName == "textblocks" ) { TQDomNode node = telement.firstChild(); TQDomElement element = node.toElement(); // if there is nothing to begin with, then we don't worry about it loadCheckForChildrenOK = element.isNull() ? true : false; while( !element.isNull() ) { TQString name = element.tagName(); if( name == "codecomment" ) { CodeComment * block = new JavaCodeComment(this); block->loadFromXMI(element); if(!addTextBlock(block)) { kError()<<"loadFromXMI : unable to add codeComment to :"<deleteLater(); } else loadCheckForChildrenOK= true; } else if( name == "codeaccessormethod" || name == "ccfdeclarationcodeblock" ) { TQString acctag = element.attribute("tag",""); // search for our method in the TextBlock * tb = findCodeClassFieldTextBlockByTag(acctag); if(!tb || !addTextBlock(tb)) { kError()<<"loadFromXMI : unable to add codeclassfield child method to:"<loadFromXMI(element); if(!addTextBlock(block)) { kError()<<"loadFromXMI : unable to add codeBlock to :"<deleteLater(); } else loadCheckForChildrenOK= true; } else if( name == "codeblockwithcomments" ) { CodeBlockWithComments * block = newCodeBlockWithComments(); block->loadFromXMI(element); if(!addTextBlock(block)) { kError()<<"loadFromXMI : unable to add codeBlockwithcomments to:"<deleteLater(); } else loadCheckForChildrenOK= true; } else if( name == "header" ) { // do nothing.. this is treated elsewhere } else if( name == "hierarchicalcodeblock" ) { HierarchicalCodeBlock * block = newHierarchicalCodeBlock(); block->loadFromXMI(element); if(!addTextBlock(block)) { kError()<<"Unable to add hierarchicalcodeBlock to:"<deleteLater(); } else loadCheckForChildrenOK= true; } else if( name == "codeoperation" ) { // find the code operation by id TQString id = element.attribute("parent_id","-1"); UMLObject * obj = UMLApp::app()->getDocument()->findObjectById(STR2ID(id)); UMLOperation * op = dynamic_cast(obj); if(op) { CodeOperation * block = new JavaCodeOperation(this, op); block->loadFromXMI(element); if(addTextBlock(block)) loadCheckForChildrenOK= true; else { kError()<<"Unable to add codeoperation to:"<deleteLater(); } } else kError()<<"Unable to find operation create codeoperation for:"<loadFromXMI(element); if(!addTextBlock(block)) { kError()<<"Unable to add java code declaration block to:"<deleteLater(); } else loadCheckForChildrenOK= true; } // This last item is only needed for extreme debugging conditions // (E.g. making new codeclassdocument loader) // else // kDebug()<<" LoadFromXMI: Got strange tag in text block stack:"<(this); if(test) { kWarning()<<" loadChildBlocks : unable to initialize any child blocks in doc: "<getFileName()<<" "<(this); if(hb) kWarning()<<" loadChildBlocks : unable to initialize any child blocks in Hblock: "<getTag()<<" "<setTag("ClassDeclBlock"); } return classDeclCodeBlock; } void JavaClassifierCodeDocument::resetTextBlocks() { // all special pointers to text blocks need to be zero'd out operationsBlock = 0; constructorBlock = 0; classDeclCodeBlock = 0; // now do traditional release of text blocks. ClassifierCodeDocument::resetTextBlocks(); } // This method will cause the class to rebuild its text representation. // based on the parent classifier object. // For any situation in which this is called, we are either building the code // document up, or replacing/regenerating the existing auto-generated parts. As // such, we will want to insert everything we resonablely will want // during creation. We can set various parts of the document (esp. the // comments) to appear or not, as needed. void JavaClassifierCodeDocument::updateContent( ) { // Gather info on the various fields and parent objects of this class... UMLClassifier * c = getParentClassifier(); CodeGenerationPolicy * commonPolicy = UMLApp::app()->getCommonPolicy(); CodeGenPolicyExt * pe = UMLApp::app()->getPolicyExt(); JavaCodeGenerationPolicy * policy = dynamic_cast(pe); // first, set the global flag on whether or not to show classfield info // This depends on whether or not we have attribute/association classes CodeClassFieldList * cfList = getCodeClassFieldList(); for(CodeClassField * field = cfList->first(); field; field = cfList->next()) if(field->parentIsAttribute()) field->setWriteOutMethods(policy->getAutoGenerateAttribAccessors()); else field->setWriteOutMethods(policy->getAutoGenerateAssocAccessors()); // attribute-based ClassFields // we do it this way to have the static fields sorted out from regular ones CodeClassFieldList staticAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, true); CodeClassFieldList attribClassFields = getSpecificClassFields (CodeClassField::Attribute, false); // association-based ClassFields // don't care if they are static or not..all are lumped together CodeClassFieldList plainAssocClassFields = getSpecificClassFields ( CodeClassField::PlainAssociation ); CodeClassFieldList aggregationClassFields = getSpecificClassFields ( CodeClassField::Aggregation ); CodeClassFieldList compositionClassFields = getSpecificClassFields ( CodeClassField::Composition ); bool isInterface = parentIsInterface(); bool hasOperationMethods = c->getOpList().last() ? true : false; TQString endLine = commonPolicy->getNewLineEndingChars(); // a shortcut..so we don't have to call this all the time // // START GENERATING CODE/TEXT BLOCKS and COMMENTS FOR THE DOCUMENT // // // PACKAGE CODE BLOCK // TQString pkgs = getPackage(); pkgs.replace(TQRegExp("::"), "."); TQString packageText = getPackage().isEmpty() ? "" : "package "+pkgs+';'+endLine; CodeBlockWithComments * pblock = addOrUpdateTaggedCodeBlockWithComments("packages", packageText, "", 0, false); if(packageText.isEmpty() && pblock->getContentType() == CodeBlock::AutoGenerated) pblock->setWriteOutText(false); else pblock->setWriteOutText(true); // IMPORT CODEBLOCK // // Q: Why all utils? Isnt just List and Vector the only classes we are using? // A: doesn't matter at all; its more readable to just include '*' and java compilers // don't slow down or anything. (TZ) TQString importStatement = ""; if ( hasObjectVectorClassFields() ) importStatement.append("import java.util.*;"); //only import classes in a different package from this class UMLPackageList imports; TQMap packageMap; // so we don't repeat packages CodeGenerator::findObjectsRelated(c,imports); for(UMLPackage *con = imports.first(); con ; con = imports.next()) // NO (default) datatypes in the import statement.. use defined // ones whould be possible, but no idea how to do that...at least for now. // Dynamic casting is slow..not an optimal way to do this. if (!packageMap.contains(con) && con->getBaseType() != Uml::ot_Datatype) { packageMap.insert(con, con->getPackage()); // now, we DON'T need to import classes that are already in our own package // (that is, IF a package is specified). Otherwise, we should have a declaration. if (con->getPackage() != c->getPackage() || (c->getPackage().isEmpty() && con->getPackage().isEmpty())) { importStatement.append(endLine+"import "); if(!con->getPackage().isEmpty()) importStatement.append(con->getPackage()+'.'); importStatement.append(CodeGenerator::cleanName(con->getName())+';'); } } // now, add/update the imports codeblock CodeBlockWithComments * iblock = addOrUpdateTaggedCodeBlockWithComments("imports", importStatement, "", 0, false); if(importStatement.isEmpty() && iblock->getContentType() == CodeBlock::AutoGenerated) iblock->setWriteOutText(false); else iblock->setWriteOutText(true); // CLASS DECLARATION BLOCK // // get the declaration block. If its not already present, add it too JavaClassDeclarationBlock * myClassDeclCodeBlock = getClassDecl(); addTextBlock(myClassDeclCodeBlock); // note: wont add if already present // NOW create document in sections.. // now we want to populate the body of our class // our layout is the following general groupings of code blocks: // start java classifier document // header comment // package code block // import code block // class declaration // section: // - class field declaration section comment // - class field declarations (0+ codeblocks) // section: // - methods section comment // sub-section: constructor ops // - constructor method section comment // - constructor methods (0+ codeblocks) // sub-section: accessors // - accessor method section comment // - static accessor methods (0+ codeblocks) // - non-static accessor methods (0+ codeblocks) // sub-section: non-constructor ops // - operation method section comment // - operations (0+ codeblocks) // end class declaration // end java classifier document // Q: Why use the more complicated scheme of arranging code blocks within codeblocks? // A: This will allow us later to preserve the format of our document so that if // codeblocks are added, they may be easily added in the correct place, rather than at // the end of the document, or by using a difficult algorithm to find the location of // the last appropriate code block sibling (which may not exist.. for example user adds // a constructor operation, but there currently are no constructor code blocks // within the document). // // * CLASS FIELD declaration section // // get/create the field declaration code block HierarchicalCodeBlock * fieldDeclBlock = myClassDeclCodeBlock->getHierarchicalCodeBlock("fieldsDecl", "Fields", 1); // Update the comment: we only set comment to appear under the following conditions CodeComment * fcomment = fieldDeclBlock->getComment(); if (isInterface || (!forceDoc() && !hasClassFields()) ) fcomment->setWriteOutText(false); else fcomment->setWriteOutText(true); // now actually declare the fields within the appropriate HCodeBlock declareClassFields(staticAttribClassFields, fieldDeclBlock); declareClassFields(attribClassFields, fieldDeclBlock); declareClassFields(plainAssocClassFields, fieldDeclBlock); declareClassFields(aggregationClassFields, fieldDeclBlock); declareClassFields(compositionClassFields, fieldDeclBlock); // // METHODS section // // get/create the method codeblock HierarchicalCodeBlock * methodsBlock = myClassDeclCodeBlock->getHierarchicalCodeBlock("methodsBlock", "Methods", 1); // Update the section comment CodeComment * methodsComment = methodsBlock->getComment(); // set conditions for showing this comment if (!forceDoc() && !hasClassFields() && !hasOperationMethods) methodsComment->setWriteOutText(false); else methodsComment->setWriteOutText(true); // METHODS sub-section : constructor methods // // get/create the constructor codeblock HierarchicalCodeBlock * constBlock = methodsBlock->getHierarchicalCodeBlock("constructorMethods", "Constructors", 1); constructorBlock = constBlock; // record this codeblock for later, when operations are updated // special condiions for showing comment: only when autogenerateding empty constructors // Although, we *should* check for other constructor methods too CodeComment * constComment = constBlock->getComment(); CodeGenerationPolicy *pol = UMLApp::app()->getCommonPolicy(); if (!forceDoc() && (isInterface || !pol->getAutoGenerateConstructors())) constComment->setWriteOutText(false); else constComment->setWriteOutText(true); // add/get the empty constructor TQString JavaClassName = getJavaClassName(c->getName()); TQString emptyConstStatement = "public "+JavaClassName+" ( ) { }"; CodeBlockWithComments * emptyConstBlock = constBlock->addOrUpdateTaggedCodeBlockWithComments("emptyconstructor", emptyConstStatement, "Empty Constructor", 1, false); // Now, as an additional condition we only show the empty constructor block // IF it was desired to be shown if(parentIsClass() && pol->getAutoGenerateConstructors()) emptyConstBlock->setWriteOutText(true); else emptyConstBlock->setWriteOutText(false); // METHODS subsection : ACCESSOR METHODS // // get/create the accessor codeblock HierarchicalCodeBlock * accessorBlock = methodsBlock->getHierarchicalCodeBlock("accessorMethods", "Accessor Methods", 1); // set conditions for showing section comment CodeComment * accessComment = accessorBlock->getComment(); if (!forceDoc() && !hasClassFields()) accessComment->setWriteOutText(false); else accessComment->setWriteOutText(true); // now, 2 sub-sub sections in accessor block // add/update accessor methods for attributes HierarchicalCodeBlock * staticAccessors = accessorBlock->getHierarchicalCodeBlock("staticAccessorMethods", "", 1); staticAccessors->getComment()->setWriteOutText(false); // never write block comment staticAccessors->addCodeClassFieldMethods(staticAttribClassFields); staticAccessors->addCodeClassFieldMethods(attribClassFields); // add/update accessor methods for associations HierarchicalCodeBlock * regularAccessors = accessorBlock->getHierarchicalCodeBlock("regularAccessorMethods", "", 1); regularAccessors->getComment()->setWriteOutText(false); // never write block comment regularAccessors->addCodeClassFieldMethods(plainAssocClassFields); regularAccessors->addCodeClassFieldMethods(aggregationClassFields); regularAccessors->addCodeClassFieldMethods(compositionClassFields); // METHODS subsection : Operation methods (which arent constructors) // // get/create the operations codeblock operationsBlock = methodsBlock->getHierarchicalCodeBlock("operationMethods", "Operations", 1); // set conditions for showing section comment CodeComment * ocomment = operationsBlock->getComment(); if (!forceDoc() && !hasOperationMethods ) ocomment->setWriteOutText(false); else ocomment->setWriteOutText(true); } #include "javaclassifiercodedocument.moc"