// 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 CPPHeaderCodeDocument::updateContent() { // Gather info on the various fields and parent objects of this class... UMLClassifier * c = getParentClassifier(); Q_ASSERT(c != NULL); CodeGenPolicyExt *pe = UMLApp::app()->policyExt(); CPPCodeGenerationPolicy * policy = dynamic_cast<CPPCodeGenerationPolicy*>(pe); // first, set the global flag on whether or not to show classfield info const CodeClassFieldList * cfList = getCodeClassFieldList(); CodeClassFieldList::const_iterator it = cfList->begin(); CodeClassFieldList::const_iterator end = cfList->end(); for(; it != end; ++it) (*it)->setWriteOutMethods(policy->getAutoGenerateAccessors()); // attribute-based ClassFields // we do it this way to have the static fields sorted out from regular ones CodeClassFieldList staticPublicAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, true, Uml::Visibility::Public); CodeClassFieldList publicAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, false, Uml::Visibility::Public); CodeClassFieldList staticProtectedAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, true, Uml::Visibility::Protected); CodeClassFieldList protectedAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, false, Uml::Visibility::Protected); CodeClassFieldList staticPrivateAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, true, Uml::Visibility::Private); CodeClassFieldList privateAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, false, Uml::Visibility::Private); // association-based ClassFields // don't care if they are static or not..all are lumped together CodeClassFieldList publicPlainAssocClassFields = getSpecificClassFields (CodeClassField::PlainAssociation, Uml::Visibility::Public); CodeClassFieldList publicAggregationClassFields = getSpecificClassFields (CodeClassField::Aggregation, Uml::Visibility::Public); CodeClassFieldList publicCompositionClassFields = getSpecificClassFields (CodeClassField::Composition, Uml::Visibility::Public); CodeClassFieldList protPlainAssocClassFields = getSpecificClassFields (CodeClassField::PlainAssociation, Uml::Visibility::Protected); CodeClassFieldList protAggregationClassFields = getSpecificClassFields (CodeClassField::Aggregation, Uml::Visibility::Protected); CodeClassFieldList protCompositionClassFields = getSpecificClassFields (CodeClassField::Composition, Uml::Visibility::Protected); CodeClassFieldList privPlainAssocClassFields = getSpecificClassFields (CodeClassField::PlainAssociation, Uml::Visibility::Private); CodeClassFieldList privAggregationClassFields = getSpecificClassFields (CodeClassField::Aggregation, Uml::Visibility::Private); CodeClassFieldList privCompositionClassFields = getSpecificClassFields (CodeClassField::Composition, Uml::Visibility::Private); bool hasOperationMethods = false; UMLOperationList list = c->getOpList(); hasOperationMethods = ! list.isEmpty(); bool hasNamespace = false; bool isEnumeration = false; bool isInterface = parentIsInterface(); bool hasclassFields = hasClassFields(); bool forcedoc = UMLApp::app()->commonPolicy()->getCodeVerboseDocumentComments(); QString endLine = UMLApp::app()->commonPolicy()->getNewLineEndingChars(); UMLClassifierList superclasses = c->findSuperClassConcepts(); // START GENERATING CODE/TEXT BLOCKS and COMMENTS FOR THE DOCUMENT // // Write the hash define stuff to prevent multiple parsing/inclusion of header QString cppClassName = CodeGenerator::cleanName(c->name()); QString hashDefine = CodeGenerator::cleanName(c->name().toUpper().simplified()); QString defText = QLatin1String("#ifndef ") + hashDefine + QLatin1String("_H") + endLine + QLatin1String("#define ") + hashDefine + QLatin1String("_H"); addOrUpdateTaggedCodeBlockWithComments(QLatin1String("hashDefBlock"), defText, QString(), 0, false); // INCLUDE 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 cpp compilers // don't slow down or anything. (TZ) QString includeStatement; bool stringGlobal = policy->stringIncludeIsGlobal(); QString sStartBrak = stringGlobal ? QLatin1String("<") : QLatin1String("\""); QString sEndBrak = stringGlobal ? QLatin1String(">") : QLatin1String("\""); includeStatement.append(QLatin1String("#include ") + sStartBrak + policy->getStringClassNameInclude() + sEndBrak + endLine); if (hasObjectVectorClassFields()) { bool vecGlobal = policy->vectorIncludeIsGlobal(); QString vStartBrak = vecGlobal ? QLatin1String("<") : QLatin1String("\""); QString vEndBrak = vecGlobal ? QLatin1String(">") : QLatin1String("\""); QString value =QLatin1String("#include ") + vStartBrak + policy->getVectorClassNameInclude() + vEndBrak; includeStatement.append(value + endLine); } //only include classes in a different package from this class UMLPackageList includes; QMap<UMLPackage *, QString> packageMap; // so we don't repeat packages CodeGenerator::findObjectsRelated(c, includes); foreach(UMLPackage* con, includes) { if (con->baseType() != UMLObject::ot_Datatype && !packageMap.contains(con)) { packageMap.insert(con, con->package()); if(con != getParentClassifier()) includeStatement.append(QLatin1String("#include \"") + CodeGenerator::cleanName(con->name().toLower()) + QLatin1String(".h\"") + endLine); } } // now, add/update the includes codeblock CodeBlockWithComments * inclBlock = addOrUpdateTaggedCodeBlockWithComments(QLatin1String("includes"), includeStatement, QString(), 0, false); if(includeStatement.isEmpty() && inclBlock->contentType() == CodeBlock::AutoGenerated) inclBlock->setWriteOutText(false); else inclBlock->setWriteOutText(true); // Using QString usingStatement; foreach(UMLClassifier* classifier, superclasses) { if(classifier->package()!=c->package() && !classifier->package().isEmpty()) { usingStatement.append(QLatin1String("using ") + CodeGenerator::cleanName(c->package()) + QLatin1String("::") + cleanName(c->name()) + QLatin1Char(';') + endLine); } } CodeBlockWithComments * usingBlock = addOrUpdateTaggedCodeBlockWithComments(QLatin1String("using"), usingStatement, QString(), 0, false); if(usingStatement.isEmpty() && usingBlock->contentType() == CodeBlock::AutoGenerated) usingBlock->setWriteOutText(false); else usingBlock->setWriteOutText(true); // namespace // This needs special treatment. We cant use "nowriteouttext" for this, as // that will prevent the class declaration from being written. Instead, we // check if "hasNamspace" is true or not, and then indent the remaining code // appropriately as well as set the start/end text of this namespace block. if (c->umlPackage() && policy->getPackageIsNamespace()) hasNamespace = true; else hasNamespace = false; // set start/end text of namespace block m_namespaceBlock = getHierarchicalCodeBlock(QLatin1String("namespace"), QLatin1String("Namespace"), 0); if(hasNamespace) { UMLPackageList pkgList = c->packages(); QString pkgs; UMLPackage *pkg; foreach (pkg, pkgList) { pkgs += QLatin1String("namespace ") + CodeGenerator::cleanName(pkg->name()) + QLatin1String(" { "); } m_namespaceBlock->setStartText(pkgs); QString closingBraces; foreach (pkg, pkgList) { closingBraces += QLatin1String("} "); }
// 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 DClassifierCodeDocument::updateContent() { // Gather info on the various fields and parent objects of this class... UMLClassifier * c = getParentClassifier(); Q_ASSERT(c != 0); CodeGenerationPolicy * commonPolicy = UMLApp::app()->commonPolicy(); CodeGenPolicyExt * pe = UMLApp::app()->policyExt(); DCodeGenerationPolicy * policy = dynamic_cast<DCodeGenerationPolicy*>(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 const CodeClassFieldList * cfList = getCodeClassFieldList(); CodeClassFieldList::const_iterator it = cfList->begin(); CodeClassFieldList::const_iterator end = cfList->end(); for (; it != end; ++it) { CodeClassField * field = *it; 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 = false; UMLOperationList list = c->getOpList(); hasOperationMethods = ! list.isEmpty(); QString 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 // QString pkgs = getPackage(); pkgs.replace(QRegExp(QLatin1String("::")), QLatin1String(".")); QString packageText = getPackage().isEmpty() ? QString() : QString(QLatin1String("package ")+pkgs+QLatin1Char(';')+endLine); CodeBlockWithComments * pblock = addOrUpdateTaggedCodeBlockWithComments(QLatin1String("packages"), packageText, QString(), 0, false); if (packageText.isEmpty() && pblock->contentType() == CodeBlock::AutoGenerated) pblock->setWriteOutText(false); else pblock->setWriteOutText(true); // IMPORT CODEBLOCK // // Q: Why all utils? Aren't just List and Vector the only classes we are using? // A: doesn't matter at all; it is more readable to just include '*' and d compilers // don't slow down or anything. (TZ) QString importStatement; if (hasObjectVectorClassFields()) importStatement.append(QLatin1String("import d.util.*;")); //only import classes in a different package from this class UMLPackageList imports; QMap<UMLPackage*, QString> packageMap; // so we don't repeat packages CodeGenerator::findObjectsRelated(c, imports); for (UMLPackageListIt importsIt(imports); importsIt.hasNext();) { UMLPackage *con = importsIt.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->isUMLDatatype()) { packageMap.insert(con, con->package()); // 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->package() != c->package() || (c->package().isEmpty() && con->package().isEmpty())) { importStatement.append(endLine+QLatin1String("import ")); if (!con->package().isEmpty()) importStatement.append(con->package()+QLatin1Char('.')); importStatement.append(CodeGenerator::cleanName(con->name())+QLatin1Char(';')); } } } // now, add/update the imports codeblock CodeBlockWithComments * iblock = addOrUpdateTaggedCodeBlockWithComments(QLatin1String("imports"), importStatement, QString(), 0, false); if (importStatement.isEmpty() && iblock->contentType() == CodeBlock::AutoGenerated) iblock->setWriteOutText(false); else iblock->setWriteOutText(true); // CLASS DECLARATION BLOCK // // get the declaration block. If it is not already present, add it too DClassDeclarationBlock * 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 d 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 d 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(QLatin1String("fieldsDecl"), QLatin1String("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(QLatin1String("methodsBlock"), QLatin1String("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(QLatin1String("constructorMethods"), QLatin1String("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()->commonPolicy(); if (!forceDoc() && (isInterface || !pol->getAutoGenerateConstructors())) constComment->setWriteOutText(false); else constComment->setWriteOutText(true); // add/get the empty constructor QString DClassName = getDClassName(c->name()); QString emptyConstStatement = QLatin1String("public ")+DClassName+QLatin1String(" () { }"); CodeBlockWithComments * emptyConstBlock = constBlock->addOrUpdateTaggedCodeBlockWithComments(QLatin1String("emptyconstructor"), emptyConstStatement, QLatin1String("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(QLatin1String("accessorMethods"), QLatin1String("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(QLatin1String("staticAccessorMethods"), QString(), 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(QLatin1String("regularAccessorMethods"), QString(), 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(QLatin1String("operationMethods"), QLatin1String("Operations"), 1); // set conditions for showing section comment CodeComment * ocomment = operationsBlock->getComment(); if (!forceDoc() && !hasOperationMethods) ocomment->setWriteOutText(false); else ocomment->setWriteOutText(true); }