You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1284 lines
48 KiB
1284 lines
48 KiB
/***************************************************************************
|
|
* cppwriter.cpp - description *
|
|
* This is the "old" code generator that does not support code editing *
|
|
* in the Modeller but uses significantly less file space because the *
|
|
* source code is not replicated in the XMI file. *
|
|
* *
|
|
* copyright : (C) 2003 Brian Thomas brian.thomas@gsfc.nasa.gov *
|
|
* (C) 2004-2006 Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
|
|
* *
|
|
***************************************************************************
|
|
* *
|
|
* 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. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
// own header
|
|
#include "cppwriter.h"
|
|
// qt/kde includes
|
|
#include <tqfile.h>
|
|
#include <tqtextstream.h>
|
|
#include <tqregexp.h>
|
|
#include <kdebug.h>
|
|
// app includes
|
|
#include "classifierinfo.h"
|
|
#include "codegen_utils.h"
|
|
#include "../uml.h"
|
|
#include "../umldoc.h"
|
|
#include "../classifier.h"
|
|
#include "../operation.h"
|
|
#include "../template.h"
|
|
#include "../umltemplatelist.h"
|
|
#include "../umlclassifierlistitemlist.h"
|
|
#include "../classifierlistitem.h"
|
|
#include "../model_utils.h"
|
|
#include "../codegenerationpolicy.h"
|
|
|
|
// 3-14-2003: this code developed from the javawriter with parts of the
|
|
// original cppwriter by Luis De la Parra Blum
|
|
|
|
CppWriter::CppWriter()
|
|
{
|
|
// Probably we could resolve this better through the use of templates,
|
|
// but its a quick n dirty fix for the timebeing.. until codegeneration
|
|
// template system is in place.
|
|
// You can insert code here. 3 general variables exist: "%VARNAME%"
|
|
// allows you to specify where the vector variable should be in your code,
|
|
// and "%ITEMCLASS%", if needed, where the class of the item is declared.
|
|
VECTOR_METHOD_APPEND = "%VARNAME%.push_back(add_object);"; // for std::vector
|
|
VECTOR_METHOD_REMOVE = "int i, size = %VARNAME%.size();\nfor ( i = 0; i < size; i++) {\n\t%ITEMCLASS% item = %VARNAME%.at(i);\n\tif(item == remove_object) {\n\t\tvector<%ITEMCLASS%>::iterator it = %VARNAME%.begin() + i;\n\t\t%VARNAME%.erase(it);\n\t\treturn;\n\t}\n }"; // for std::vector
|
|
VECTOR_METHOD_INIT = TQString(); // nothing to be done
|
|
/*
|
|
VECTOR_METHOD_APPEND = "%VARNAME%.append(&add_object);"; // TQt lib implementation
|
|
VECTOR_METHOD_REMOVE = "%VARNAME%.removeRef(&remove_object);"; // TQt lib implementation
|
|
VECTOR_METHOD_INIT = "%VARNAME%.setAutoDelete(false);"; // TQt library
|
|
*/
|
|
|
|
OBJECT_METHOD_INIT = "%VARNAME% = new %ITEMCLASS%( );"; // TQt library
|
|
|
|
// boolean config params
|
|
INLINE_ASSOCIATION_METHODS = false;
|
|
|
|
}
|
|
|
|
CppWriter::~CppWriter() { }
|
|
|
|
Uml::Programming_Language CppWriter::getLanguage() {
|
|
return Uml::pl_Cpp;
|
|
}
|
|
|
|
CPPCodeGenerationPolicy *CppWriter::policyExt() {
|
|
return static_cast<CPPCodeGenerationPolicy*>(UMLApp::app()->getPolicyExt());
|
|
}
|
|
|
|
void CppWriter::writeClass(UMLClassifier *c)
|
|
{
|
|
|
|
if (!c) {
|
|
kDebug() << "Cannot write class of NULL concept!\n";
|
|
return;
|
|
}
|
|
|
|
TQFile fileh, filecpp;
|
|
|
|
// find an appropriate name for our file
|
|
TQString fileName = findFileName(c, ".h");
|
|
if (fileName.isEmpty()) {
|
|
emit codeGenerated(c, false);
|
|
return;
|
|
}
|
|
|
|
// preparations
|
|
m_classifierInfo = new ClassifierInfo(c);
|
|
m_classifierInfo->fileName = fileName;
|
|
m_classifierInfo->className = cleanName(c->getName());
|
|
|
|
if (c->getVisibility() != Uml::Visibility::Implementation) {
|
|
if( !openFile(fileh, fileName)) {
|
|
emit codeGenerated(c, false);
|
|
return;
|
|
}
|
|
// write Header file
|
|
writeHeaderFile(c, fileh);
|
|
fileh.close();
|
|
}
|
|
|
|
// Determine whether the implementation file is required.
|
|
// (It is not required if the class is an enumeration.)
|
|
bool need_impl = true;
|
|
if (c->getBaseType() == Uml::ot_Enum) {
|
|
need_impl = false;
|
|
}
|
|
if (need_impl) {
|
|
fileName.replace( TQRegExp(".h$"), ".cpp");
|
|
if( !openFile(filecpp, fileName)) {
|
|
emit codeGenerated(c, false);
|
|
return;
|
|
}
|
|
// write Source file
|
|
writeSourceFile(c, filecpp);
|
|
filecpp.close();
|
|
}
|
|
|
|
// Wrap up: free m_classifierInfo, emit done code
|
|
m_classifierInfo = 0;
|
|
|
|
emit codeGenerated(c, true);
|
|
|
|
}
|
|
|
|
void CppWriter::writeHeaderFile (UMLClassifier *c, TQFile &fileh) {
|
|
|
|
// open stream for writing
|
|
TQTextStream h (&fileh);
|
|
|
|
// up the indent level to one
|
|
m_indentLevel = 1;
|
|
|
|
// write header blurb
|
|
TQString str = getHeadingFile(".h");
|
|
if(!str.isEmpty()) {
|
|
str.replace(TQRegExp("%filename%"),m_classifierInfo->fileName + ".h");
|
|
str.replace(TQRegExp("%filepath%"),fileh.name());
|
|
h << str<< m_endl;
|
|
}
|
|
|
|
// Write the hash define stuff to prevent multiple parsing/inclusion of header
|
|
TQString hashDefine = m_classifierInfo->className.upper().simplifyWhiteSpace().replace(TQRegExp(" "), "_");
|
|
writeBlankLine(h);
|
|
h << "#ifndef "<< hashDefine + "_H" << m_endl;
|
|
h << "#define "<< hashDefine + "_H" << m_endl;
|
|
|
|
writeClassDecl(c, h);
|
|
|
|
// last thing..close our hashdefine
|
|
h << m_endl << "#endif // " << hashDefine + "_H" << m_endl;
|
|
|
|
}
|
|
|
|
void CppWriter::writeHeaderAccessorMethodDecl(UMLClassifier *c, Uml::Visibility permitScope, TQTextStream &stream)
|
|
{
|
|
|
|
// attributes
|
|
writeHeaderAttributeAccessorMethods(permitScope, true, stream); // write static attributes first
|
|
writeHeaderAttributeAccessorMethods(permitScope, false, stream);
|
|
|
|
// associations
|
|
writeAssociationMethods(m_classifierInfo->plainAssociations, permitScope,
|
|
true, INLINE_ASSOCIATION_METHODS, true, c->getID(), stream);
|
|
writeAssociationMethods(m_classifierInfo->uniAssociations, permitScope,
|
|
true, INLINE_ASSOCIATION_METHODS, true, c->getID(), stream);
|
|
writeAssociationMethods(m_classifierInfo->aggregations, permitScope,
|
|
true, INLINE_ASSOCIATION_METHODS, true, c->getID(), stream);
|
|
writeAssociationMethods(m_classifierInfo->compositions, permitScope,
|
|
true, INLINE_ASSOCIATION_METHODS, false, c->getID(), stream);
|
|
|
|
writeBlankLine(stream);
|
|
|
|
}
|
|
|
|
void CppWriter::writeHeaderFieldDecl(UMLClassifier *c, Uml::Visibility permitScope, TQTextStream &stream)
|
|
{
|
|
// attributes
|
|
writeAttributeDecls(permitScope, true, stream); // write static attributes first
|
|
writeAttributeDecls(permitScope, false, stream);
|
|
|
|
// associations
|
|
writeAssociationDecls(m_classifierInfo->plainAssociations, permitScope, c->getID(), stream);
|
|
writeAssociationDecls(m_classifierInfo->uniAssociations, permitScope, c->getID(), stream);
|
|
writeAssociationDecls(m_classifierInfo->aggregations, permitScope, c->getID(), stream);
|
|
writeAssociationDecls(m_classifierInfo->compositions, permitScope, c->getID(), stream);
|
|
|
|
}
|
|
|
|
void CppWriter::writeSourceFile (UMLClassifier *c, TQFile &filecpp ) {
|
|
|
|
// open stream for writing
|
|
TQTextStream cpp (&filecpp);
|
|
|
|
// set the starting indentation at zero
|
|
m_indentLevel = 0;
|
|
|
|
//try to find a heading file (license, coments, etc)
|
|
TQString str;
|
|
str = getHeadingFile(".cpp");
|
|
if(!str.isEmpty()) {
|
|
str.replace(TQRegExp("%filename%"),m_classifierInfo->fileName + ".cpp");
|
|
str.replace(TQRegExp("%filepath%"),filecpp.name());
|
|
cpp << str << m_endl;
|
|
}
|
|
|
|
// IMPORT statements
|
|
// Q: Why all utils? Isnt just List and Vector the only classes we are using?
|
|
// Our import *should* also look at operations, and check that objects being
|
|
// used arent in another package (and thus need to be explicitly imported here).
|
|
cpp << "#include \"" << m_classifierInfo->className << ".h\"" << m_endl;
|
|
writeBlankLine(cpp);
|
|
|
|
if (c->getVisibility() == Uml::Visibility::Implementation) {
|
|
writeClassDecl(c, cpp);
|
|
}
|
|
|
|
// Start body of class
|
|
|
|
// Constructors: anything we more we need to do here ?
|
|
//
|
|
if(!m_classifierInfo->isInterface)
|
|
writeConstructorMethods(cpp);
|
|
|
|
// METHODS
|
|
//
|
|
|
|
// write comment for section IF needed
|
|
TQString indent = getIndent();
|
|
if (forceDoc() || m_classifierInfo->hasAccessorMethods || m_classifierInfo->hasOperationMethods)
|
|
{
|
|
|
|
writeComment(" ", indent, cpp);
|
|
writeComment("Methods", indent, cpp);
|
|
writeComment(" ", indent, cpp);
|
|
writeBlankLine(cpp);
|
|
writeBlankLine(cpp);
|
|
}
|
|
|
|
// write comment for sub-section IF needed
|
|
if (forceDoc() || m_classifierInfo->hasAccessorMethods )
|
|
{
|
|
writeComment("Accessor methods", indent, cpp);
|
|
writeComment(" ", indent, cpp);
|
|
writeBlankLine(cpp);
|
|
}
|
|
|
|
// Accessor methods for attributes
|
|
const bool bInlineAccessors = policyExt()->getAccessorsAreInline();
|
|
if (!bInlineAccessors && m_classifierInfo->hasAttributes)
|
|
{
|
|
writeAttributeMethods(&(m_classifierInfo->static_atpub), Uml::Visibility::Public, false, true, !bInlineAccessors, cpp);
|
|
writeAttributeMethods(&(m_classifierInfo->atpub), Uml::Visibility::Public, false, false, !bInlineAccessors, cpp);
|
|
writeAttributeMethods(&(m_classifierInfo->static_atprot), Uml::Visibility::Protected, false, true, !bInlineAccessors, cpp);
|
|
writeAttributeMethods(&(m_classifierInfo->atprot), Uml::Visibility::Protected, false, false, !bInlineAccessors, cpp);
|
|
writeAttributeMethods(&(m_classifierInfo->static_atpriv), Uml::Visibility::Private, false, true, !bInlineAccessors, cpp);
|
|
writeAttributeMethods(&(m_classifierInfo->atpriv), Uml::Visibility::Private, false, false, !bInlineAccessors, cpp);
|
|
}
|
|
|
|
// accessor methods for associations
|
|
|
|
// public
|
|
writeAssociationMethods(m_classifierInfo->plainAssociations, Uml::Visibility::Public, false,
|
|
!INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
|
|
writeAssociationMethods(m_classifierInfo->uniAssociations, Uml::Visibility::Public, false,
|
|
!INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
|
|
writeAssociationMethods(m_classifierInfo->aggregations, Uml::Visibility::Public, false,
|
|
!INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
|
|
writeAssociationMethods(m_classifierInfo->compositions, Uml::Visibility::Public, false,
|
|
!INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
|
|
|
|
// protected
|
|
writeAssociationMethods(m_classifierInfo->plainAssociations, Uml::Visibility::Protected, false,
|
|
!INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
|
|
writeAssociationMethods(m_classifierInfo->uniAssociations, Uml::Visibility::Protected, false,
|
|
!INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
|
|
writeAssociationMethods(m_classifierInfo->aggregations, Uml::Visibility::Protected, false,
|
|
!INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
|
|
writeAssociationMethods(m_classifierInfo->compositions, Uml::Visibility::Protected, false,
|
|
!INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
|
|
|
|
|
|
// private
|
|
writeAssociationMethods(m_classifierInfo->plainAssociations, Uml::Visibility::Private, false,
|
|
!INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
|
|
writeAssociationMethods(m_classifierInfo->uniAssociations, Uml::Visibility::Private, false,
|
|
!INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
|
|
writeAssociationMethods(m_classifierInfo->aggregations, Uml::Visibility::Private, false,
|
|
!INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
|
|
writeAssociationMethods(m_classifierInfo->compositions, Uml::Visibility::Private, false,
|
|
!INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
|
|
writeBlankLine(cpp);
|
|
|
|
// Other operation methods -- all other operations are now written
|
|
//
|
|
|
|
// write comment for sub-section IF needed
|
|
if (forceDoc() || m_classifierInfo->hasOperationMethods)
|
|
{
|
|
writeComment("Other methods", indent, cpp);
|
|
writeComment(" ", indent, cpp);
|
|
writeBlankLine(cpp);
|
|
}
|
|
|
|
if(!policyExt()->getOperationsAreInline())
|
|
{
|
|
writeOperations(c,false,Uml::Visibility::Public,cpp);
|
|
writeOperations(c,false,Uml::Visibility::Protected,cpp);
|
|
writeOperations(c,false,Uml::Visibility::Private,cpp);
|
|
}
|
|
|
|
// Yep, bringing up the back of the bus, our initialization method for attributes
|
|
writeInitAttibuteMethod (cpp);
|
|
|
|
writeBlankLine(cpp);
|
|
|
|
}
|
|
|
|
void CppWriter::writeClassDecl(UMLClassifier *c, TQTextStream &cpp)
|
|
{
|
|
UMLClassifierList superclasses = m_classifierInfo->superclasses;
|
|
for(UMLClassifier *classifier = superclasses.first(); classifier ;classifier = superclasses.next()) {
|
|
TQString headerName = findFileName(classifier, ".h");
|
|
if (!headerName.isEmpty()) {
|
|
cpp << "#include \"" << headerName << "\"" << m_endl;
|
|
}
|
|
}
|
|
|
|
writeBlankLine(cpp);
|
|
cpp << "#include " << policyExt()->getStringClassNameInclude() << m_endl;
|
|
if(m_classifierInfo->hasVectorFields)
|
|
{
|
|
cpp << "#include " << policyExt()->getVectorClassNameInclude() << m_endl;
|
|
writeBlankLine(cpp);
|
|
}
|
|
|
|
if(m_classifierInfo->hasAssociations)
|
|
{
|
|
// write all includes we need to include other classes, that arent us.
|
|
printAssociationIncludeDecl (m_classifierInfo->plainAssociations, c->getID(), cpp);
|
|
printAssociationIncludeDecl (m_classifierInfo->uniAssociations, c->getID(), cpp);
|
|
printAssociationIncludeDecl (m_classifierInfo->aggregations, c->getID(), cpp);
|
|
printAssociationIncludeDecl (m_classifierInfo->compositions, c->getID(), cpp);
|
|
|
|
writeBlankLine(cpp);
|
|
}
|
|
|
|
|
|
for(UMLClassifier *classifier = superclasses.first(); classifier ; classifier = superclasses.next()) {
|
|
if(classifier->getPackage()!=c->getPackage() && !classifier->getPackage().isEmpty()) {
|
|
cpp << "using " << cleanName(classifier->getPackage()) << "::" << cleanName(classifier->getName()) << ";" << m_endl;
|
|
}
|
|
}
|
|
|
|
if(!c->getPackage().isEmpty() && policyExt()->getPackageIsNamespace())
|
|
cpp << m_endl << "namespace " << cleanName(c->getPackage()) << " {" << m_endl << m_endl;
|
|
|
|
//Write class Documentation if there is somthing or if force option
|
|
if(forceDoc() || !c->getDoc().isEmpty()) {
|
|
cpp << m_endl << "/**" << m_endl;
|
|
cpp << " * class " << m_classifierInfo->className << m_endl;
|
|
cpp << formatDoc(c->getDoc()," * ");
|
|
cpp << " */";
|
|
writeBlankLine(cpp);
|
|
writeBlankLine(cpp);
|
|
}
|
|
|
|
//check if class is abstract and / or has abstract methods
|
|
if((c->getAbstract() || m_classifierInfo->isInterface )
|
|
&& !hasAbstractOps(c))
|
|
cpp << "/******************************* Abstract Class ****************************" << m_endl
|
|
<<m_classifierInfo->className << " does not have any pure virtual methods, but its author" << m_endl
|
|
<<" defined it as an abstract class, so you should not use it directly." << m_endl
|
|
<<" Inherit from it instead and create only objects from the derived classes" << m_endl
|
|
<<"*****************************************************************************/" << m_endl << m_endl;
|
|
|
|
if (c->getBaseType() == Uml::ot_Enum) {
|
|
UMLClassifierListItemList litList = c->getFilteredList(Uml::ot_EnumLiteral);
|
|
uint i = 0;
|
|
cpp << "enum " << m_classifierInfo->className << " {" << m_endl;
|
|
for (UMLClassifierListItem *lit = litList.first(); lit; lit = litList.next()) {
|
|
TQString enumLiteral = cleanName(lit->getName());
|
|
cpp << getIndent() << enumLiteral;
|
|
if (++i < litList.count())
|
|
cpp << ",";
|
|
cpp << m_endl;
|
|
}
|
|
cpp << m_endl << "};" << m_endl; // end of class header
|
|
if(!c->getPackage().isEmpty() && policyExt()->getPackageIsNamespace())
|
|
cpp << "} // end of package namespace" << m_endl;
|
|
return;
|
|
}
|
|
|
|
// Generate template parameters.
|
|
UMLTemplateList template_params = c->getTemplateList();
|
|
if (template_params.count()) {
|
|
cpp << "template<";
|
|
for (UMLTemplate *t = template_params.first(); t; ) {
|
|
TQString formalName = t->getName();
|
|
TQString typeName = t->getTypeName();
|
|
cpp << typeName << " " << formalName;
|
|
if ((t = template_params.next()) != NULL)
|
|
cpp << ", ";
|
|
}
|
|
cpp << ">" << m_endl;
|
|
}
|
|
|
|
cpp << "class " << m_classifierInfo->className;
|
|
if (m_classifierInfo->superclasses.count() > 0)
|
|
cpp << " : ";
|
|
uint numOfSuperClasses = m_classifierInfo->superclasses.count();
|
|
uint i = 0;
|
|
for (UMLClassifier *superClass = m_classifierInfo->superclasses.first();
|
|
superClass ; superClass = m_classifierInfo->superclasses.next())
|
|
{
|
|
i++;
|
|
if (superClass->getAbstract() || superClass->isInterface())
|
|
cpp << "virtual ";
|
|
cpp << "public " << cleanName(superClass->getName());
|
|
if (i < numOfSuperClasses)
|
|
cpp << ", ";
|
|
}
|
|
|
|
cpp << m_endl << "{" << m_endl; // begin the body of the class
|
|
|
|
|
|
//declarations of operations
|
|
//
|
|
|
|
//
|
|
// write out field and operations decl grouped by visibility
|
|
//
|
|
|
|
// PUBLIC attribs/methods
|
|
cpp << "public:" << m_endl << m_endl; // print visibility decl.
|
|
// for public: constructors are first ops we print out
|
|
if(!m_classifierInfo->isInterface)
|
|
writeConstructorDecls(cpp);
|
|
writeHeaderFieldDecl(c,Uml::Visibility::Public, cpp);
|
|
writeHeaderAccessorMethodDecl(c, Uml::Visibility::Public, cpp);
|
|
writeOperations(c,true,Uml::Visibility::Public,cpp);
|
|
|
|
// PROTECTED attribs/methods
|
|
//
|
|
cpp << "protected" << ":" << m_endl << m_endl; // print visibility decl.
|
|
writeHeaderFieldDecl(c,Uml::Visibility::Protected, cpp);
|
|
writeHeaderAccessorMethodDecl(c, Uml::Visibility::Protected, cpp);
|
|
writeOperations(c,true,Uml::Visibility::Protected,cpp);
|
|
|
|
// PRIVATE attribs/methods
|
|
//
|
|
cpp << "private" << ":" << m_endl << m_endl; // print visibility decl.
|
|
writeHeaderFieldDecl(c,Uml::Visibility::Private, cpp);
|
|
writeHeaderAccessorMethodDecl(c, Uml::Visibility::Private, cpp);
|
|
writeOperations(c,true,Uml::Visibility::Private,cpp);
|
|
writeInitAttibuteDecl(cpp); // this is always private, used by constructors to initialize class
|
|
|
|
// end of class header
|
|
cpp << m_endl << "};" << m_endl;
|
|
|
|
// end of class namespace, if any
|
|
if(!c->getPackage().isEmpty() && policyExt()->getPackageIsNamespace())
|
|
cpp << "}; // end of package namespace" << m_endl;
|
|
|
|
}
|
|
|
|
void CppWriter::writeAttributeDecls (Uml::Visibility visibility, bool writeStatic, TQTextStream &stream )
|
|
{
|
|
|
|
if(m_classifierInfo->isInterface)
|
|
return;
|
|
|
|
UMLAttributeList * list;
|
|
switch (visibility)
|
|
{
|
|
case Uml::Visibility::Private:
|
|
if(writeStatic)
|
|
list = &(m_classifierInfo->static_atpriv);
|
|
else
|
|
list = &(m_classifierInfo->atpriv);
|
|
break;
|
|
|
|
case Uml::Visibility::Protected:
|
|
if(writeStatic)
|
|
list = &(m_classifierInfo->static_atprot);
|
|
else
|
|
list = &(m_classifierInfo->atprot);
|
|
break;
|
|
|
|
case Uml::Visibility::Public:
|
|
default:
|
|
if(writeStatic)
|
|
list = &(m_classifierInfo->static_atpub);
|
|
else
|
|
list = &(m_classifierInfo->atpub);
|
|
break;
|
|
}
|
|
|
|
//write documentation
|
|
if(forceDoc() || list->count() > 0)
|
|
{
|
|
TQString strVis = Codegen_Utils::capitalizeFirstLetter(visibility.toString());
|
|
TQString strStatic = writeStatic ? "Static ":"";
|
|
writeComment(strStatic + strVis + " attributes",getIndent(), stream);
|
|
writeComment(" ",getIndent(), stream);
|
|
writeBlankLine(stream);
|
|
}
|
|
|
|
if (list->count() > 0) {
|
|
|
|
// write attrib declarations now
|
|
bool isFirstAttrib = true;
|
|
TQString documentation;
|
|
for(UMLAttribute *at=list->first(); at; at=list->next())
|
|
{
|
|
|
|
// bool noPriorDocExists = documentation.isEmpty();
|
|
documentation = at->getDoc();
|
|
|
|
// add a line for code clarity IF PRIOR attrib has comment on it
|
|
// OR this line has documentation
|
|
// if(!isFirstAttrib && (!documentation.isEmpty()||!noPriorDocExists))
|
|
// writeBlankLine(stream);
|
|
|
|
isFirstAttrib = false;
|
|
|
|
TQString varName = getAttributeVariableName(at);
|
|
|
|
TQString staticValue = at->getStatic() ? "static " : "";
|
|
TQString typeName = fixTypeName(at->getTypeName());
|
|
if(!documentation.isEmpty())
|
|
writeComment(documentation, getIndent(), stream);
|
|
stream << getIndent() << staticValue << typeName << " " << varName << ";" << m_endl;
|
|
|
|
}
|
|
|
|
/*
|
|
if(list->count() > 0)
|
|
writeBlankLine(stream);
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void CppWriter::writeHeaderAttributeAccessorMethods (Uml::Visibility visibility, bool writeStatic, TQTextStream &stream )
|
|
{
|
|
// check the current policy about generate accessors as public
|
|
UMLAttributeList * list;
|
|
switch (visibility)
|
|
{
|
|
case Uml::Visibility::Private:
|
|
if(writeStatic)
|
|
list = &(m_classifierInfo->static_atpriv);
|
|
else
|
|
list = &(m_classifierInfo->atpriv);
|
|
break;
|
|
|
|
case Uml::Visibility::Protected:
|
|
if(writeStatic)
|
|
list = &(m_classifierInfo->static_atprot);
|
|
else
|
|
list = &(m_classifierInfo->atprot);
|
|
break;
|
|
|
|
case Uml::Visibility::Public:
|
|
default:
|
|
if(writeStatic)
|
|
list = &(m_classifierInfo->static_atpub);
|
|
else
|
|
list = &(m_classifierInfo->atpub);
|
|
break;
|
|
}
|
|
|
|
// switch to public
|
|
if (visibility != Uml::Visibility::Public)
|
|
stream << "public:" << m_endl << m_endl;
|
|
|
|
// write accessor methods for attribs we found
|
|
writeAttributeMethods(list, visibility, true, false, policyExt()->getAccessorsAreInline(), stream);
|
|
|
|
// switch back to previous vis.
|
|
if (visibility != Uml::Visibility::Public)
|
|
stream << visibility.toString() << ":" << m_endl << m_endl;
|
|
}
|
|
|
|
// this is for writing *source* or *header* file attribute methods
|
|
//
|
|
void CppWriter::writeAttributeMethods(UMLAttributeList *attribs,
|
|
Uml::Visibility visibility, bool isHeaderMethod,
|
|
bool isStatic,
|
|
bool writeMethodBody, TQTextStream &stream)
|
|
{
|
|
|
|
if (!policyExt()->getAutoGenerateAccessors())
|
|
return;
|
|
|
|
if (forceDoc() || attribs->count() > 0)
|
|
{
|
|
TQString strVis = Codegen_Utils::capitalizeFirstLetter(visibility.toString());
|
|
TQString strStatic = (isStatic ? " static" : "");
|
|
writeBlankLine(stream);
|
|
writeComment(strVis + strStatic + " attribute accessor methods",getIndent(),stream);
|
|
writeComment(" ",getIndent(), stream);
|
|
writeBlankLine(stream);
|
|
}
|
|
|
|
// return now if NO attributes to work on
|
|
if (attribs->count() == 0)
|
|
return;
|
|
|
|
UMLAttribute *at;
|
|
for(at=attribs->first(); at; at=attribs->next())
|
|
{
|
|
|
|
TQString varName = getAttributeVariableName(at);
|
|
TQString methodBaseName = cleanName(at->getName());
|
|
|
|
// force capitalizing the field name, this is silly,
|
|
// from what I can tell, this IS the default behavior for
|
|
// cleanName. I dunno why its not working -b.t.
|
|
methodBaseName = methodBaseName.stripWhiteSpace();
|
|
methodBaseName.replace(0,1,methodBaseName.at(0).upper());
|
|
|
|
writeSingleAttributeAccessorMethods(at->getTypeName(), varName,
|
|
methodBaseName, at->getDoc(), Uml::chg_Changeable, isHeaderMethod,
|
|
at->getStatic(), writeMethodBody, stream);
|
|
}
|
|
|
|
}
|
|
|
|
void CppWriter::writeComment(const TQString &comment, const TQString &myIndent, TQTextStream &cpp)
|
|
{
|
|
// in the case we have several line comment..
|
|
// NOTE: this part of the method has the problem of adopting UNIX newline,
|
|
// need to resolve for using with MAC/WinDoze eventually I assume
|
|
if (comment.contains(TQRegExp("\n"))) {
|
|
|
|
TQStringList lines = TQStringList::split( "\n", comment);
|
|
for(uint i= 0; i < lines.count(); i++)
|
|
{
|
|
cpp << myIndent << "// " << lines[i] << m_endl;
|
|
}
|
|
} else {
|
|
// this should be more fancy in the future, breaking it up into 80 char
|
|
// lines so that it doesn't look too bad
|
|
cpp << myIndent << "// "<< comment << m_endl;
|
|
}
|
|
}
|
|
|
|
void CppWriter::writeDocumentation(TQString header, TQString body, TQString end, TQTextStream &cpp)
|
|
{
|
|
writeBlankLine(cpp);
|
|
TQString indent = getIndent();
|
|
|
|
cpp << indent << "/**" << m_endl;
|
|
if (!header.isEmpty())
|
|
cpp << formatDoc(header, indent + " * ");
|
|
if (!body.isEmpty())
|
|
cpp << formatDoc(body, indent + " * ");
|
|
if (!end.isEmpty())
|
|
{
|
|
TQStringList lines = TQStringList::split( "\n", end);
|
|
for(uint i= 0; i < lines.count(); i++)
|
|
cpp << formatDoc(lines[i], indent + " * ");
|
|
}
|
|
cpp << indent << " */" << m_endl;
|
|
}
|
|
|
|
void CppWriter::writeAssociationDecls(UMLAssociationList associations, Uml::Visibility permitScope, Uml::IDType id, TQTextStream &h)
|
|
{
|
|
|
|
if( forceSections() || !associations.isEmpty() )
|
|
{
|
|
bool printRoleA = false, printRoleB = false;
|
|
for(UMLAssociation *a = associations.first(); a; a = associations.next())
|
|
{
|
|
|
|
// it may seem counter intuitive, but you want to insert the role of the
|
|
// *other* class into *this* class.
|
|
if (a->getObjectId(Uml::A) == id && !a->getRoleName(Uml::B).isEmpty())
|
|
printRoleB = true;
|
|
|
|
if (a->getObjectId(Uml::B) == id && !a->getRoleName(Uml::A).isEmpty())
|
|
printRoleA = true;
|
|
|
|
// First: we insert documentaion for association IF it has either role AND some documentation (!)
|
|
if ((printRoleA || printRoleB) && !(a->getDoc().isEmpty()))
|
|
writeComment(a->getDoc(), getIndent(), h);
|
|
|
|
// print RoleB decl
|
|
if (printRoleB && a->getVisibility(Uml::B) == permitScope)
|
|
{
|
|
|
|
TQString fieldClassName = cleanName(getUMLObjectName(a->getObject(Uml::B)));
|
|
writeAssociationRoleDecl(fieldClassName, a->getRoleName(Uml::B), a->getMulti(Uml::B), a->getRoleDoc(Uml::B), h);
|
|
}
|
|
|
|
// print RoleA decl
|
|
if (printRoleA && a->getVisibility(Uml::A) == permitScope)
|
|
{
|
|
TQString fieldClassName = cleanName(getUMLObjectName(a->getObject(Uml::A)));
|
|
writeAssociationRoleDecl(fieldClassName, a->getRoleName(Uml::A), a->getMulti(Uml::A), a->getRoleDoc(Uml::A), h);
|
|
}
|
|
|
|
// reset for next association in our loop
|
|
printRoleA = false;
|
|
printRoleB = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CppWriter::writeAssociationRoleDecl(TQString fieldClassName, TQString roleName, TQString multi,
|
|
TQString doc, TQTextStream &stream)
|
|
{
|
|
// ONLY write out IF there is a rolename given
|
|
// otherwise its not meant to be declared in the code
|
|
if (roleName.isEmpty())
|
|
return;
|
|
|
|
TQString indent = getIndent();
|
|
|
|
// always put space between this and prior decl, if any
|
|
writeBlankLine(stream);
|
|
|
|
if (!doc.isEmpty())
|
|
writeComment(doc, indent, stream);
|
|
|
|
// declare the association based on whether it is this a single variable
|
|
// or a List (Vector). One day this will be done correctly with special
|
|
// multiplicity object that we don't have to figure out what it means via regex.
|
|
if(multi.isEmpty() || multi.contains(TQRegExp("^[01]$")))
|
|
{
|
|
TQString fieldVarName = "m_" + roleName.lower();
|
|
|
|
// record this for later consideration of initialization IF the
|
|
// multi value requires 1 of these objects
|
|
if(ObjectFieldVariables.findIndex(fieldVarName) == -1 &&
|
|
multi.contains(TQRegExp("^1$"))
|
|
)
|
|
{
|
|
// ugh. UGLY. Storing variable name and its class in pairs.
|
|
ObjectFieldVariables.append(fieldVarName);
|
|
ObjectFieldVariables.append(fieldClassName);
|
|
}
|
|
|
|
stream << indent << fieldClassName << " * " << fieldVarName << ";" << m_endl;
|
|
}
|
|
else
|
|
{
|
|
TQString fieldVarName = "m_" + roleName.lower() + "Vector";
|
|
|
|
// record unique occurrences for later when we want to check
|
|
// for initialization of this vector
|
|
if(VectorFieldVariables.findIndex(fieldVarName) == -1)
|
|
VectorFieldVariables.append(fieldVarName);
|
|
|
|
stream << indent << policyExt()->getVectorClassName() <<"<" << fieldClassName << "*";
|
|
stream << "> " << fieldVarName << ";" << m_endl;
|
|
}
|
|
}
|
|
|
|
// for either source or header files
|
|
void CppWriter::writeAssociationMethods (UMLAssociationList associations,
|
|
Uml::Visibility permitVisib,
|
|
bool isHeaderMethod,
|
|
bool writeMethodBody,
|
|
bool writePointerVar,
|
|
Uml::IDType myID, TQTextStream &stream)
|
|
{
|
|
if( forceSections() || !associations.isEmpty() )
|
|
{
|
|
for(UMLAssociation *a = associations.first(); a; a = associations.next())
|
|
{
|
|
|
|
// insert the methods to access the role of the other
|
|
// class in the code of this one
|
|
if (a->getObjectId(Uml::A) == myID && a->getVisibility(Uml::B) == permitVisib)
|
|
{
|
|
// only write out IF there is a rolename given
|
|
if(!a->getRoleName(Uml::B).isEmpty()) {
|
|
TQString fieldClassName = getUMLObjectName(a->getObject(Uml::B)) + (writePointerVar ? " *":"");
|
|
writeAssociationRoleMethod(fieldClassName,
|
|
isHeaderMethod,
|
|
writeMethodBody,
|
|
a->getRoleName(Uml::B),
|
|
a->getMulti(Uml::B), a->getRoleDoc(Uml::B),
|
|
a->getChangeability(Uml::B), stream);
|
|
}
|
|
}
|
|
|
|
if (a->getObjectId(Uml::B) == myID && a->getVisibility(Uml::A) == permitVisib)
|
|
{
|
|
// only write out IF there is a rolename given
|
|
if(!a->getRoleName(Uml::A).isEmpty()) {
|
|
TQString fieldClassName = getUMLObjectName(a->getObject(Uml::A)) + (writePointerVar ? " *":"");
|
|
writeAssociationRoleMethod(fieldClassName,
|
|
isHeaderMethod,
|
|
writeMethodBody,
|
|
a->getRoleName(Uml::A),
|
|
a->getMulti(Uml::A),
|
|
a->getRoleDoc(Uml::A),
|
|
a->getChangeability(Uml::A),
|
|
stream);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
void CppWriter::writeAssociationRoleMethod (const TQString &fieldClassName,
|
|
bool isHeaderMethod,
|
|
bool writeMethodBody,
|
|
const TQString &roleName, const TQString &multi,
|
|
const TQString &description, Uml::Changeability_Type change,
|
|
TQTextStream &stream)
|
|
{
|
|
if(multi.isEmpty() || multi.contains(TQRegExp("^[01]$")))
|
|
{
|
|
TQString fieldVarName = "m_" + roleName.lower();
|
|
writeSingleAttributeAccessorMethods(fieldClassName, fieldVarName, roleName,
|
|
description, change, isHeaderMethod, false, writeMethodBody, stream);
|
|
}
|
|
else
|
|
{
|
|
TQString fieldVarName = "m_" + roleName.lower() + "Vector";
|
|
writeVectorAttributeAccessorMethods(fieldClassName, fieldVarName, roleName,
|
|
description, change, isHeaderMethod, writeMethodBody, stream);
|
|
}
|
|
}
|
|
|
|
void CppWriter::writeVectorAttributeAccessorMethods (
|
|
const TQString &fieldClassName, const TQString &fieldVarName,
|
|
const TQString &fieldName, const TQString &description,
|
|
Uml::Changeability_Type changeType,
|
|
bool isHeaderMethod,
|
|
bool writeMethodBody,
|
|
TQTextStream &stream)
|
|
{
|
|
|
|
TQString className = fixTypeName(fieldClassName);
|
|
TQString fldName = Codegen_Utils::capitalizeFirstLetter(fieldName);
|
|
TQString indent = getIndent();
|
|
|
|
// ONLY IF changeability is NOT Frozen
|
|
if (changeType != Uml::chg_Frozen)
|
|
{
|
|
writeDocumentation("Add a " + fldName + " object to the " + fieldVarName + " List",description,"",stream);
|
|
stream << indent << "void ";
|
|
if(!isHeaderMethod)
|
|
stream << m_classifierInfo->className << "::";
|
|
stream << "add" << fldName << " ( " << className << " add_object )";
|
|
if (writeMethodBody) {
|
|
TQString method = VECTOR_METHOD_APPEND;
|
|
method.replace(TQRegExp("%VARNAME%"),fieldVarName);
|
|
method.replace(TQRegExp("%VECTORTYPENAME%"), policyExt()->getVectorClassName());
|
|
method.replace(TQRegExp("%ITEMCLASS%"),className);
|
|
stream << indent << " {" << m_endl;
|
|
m_indentLevel++;
|
|
printTextAsSeparateLinesWithIndent(method,getIndent(),stream);
|
|
m_indentLevel--;
|
|
stream << indent << "}" << m_endl;
|
|
} else
|
|
stream << ";" << m_endl;
|
|
}
|
|
|
|
// ONLY IF changeability is Changeable
|
|
if (changeType == Uml::chg_Changeable)
|
|
{
|
|
writeDocumentation("Remove a " + fldName + " object from " + fieldVarName + " List",
|
|
description, "", stream);
|
|
stream << indent << "void ";
|
|
if(!isHeaderMethod)
|
|
stream << m_classifierInfo->className << "::";
|
|
stream << "remove" << fldName << " ( " << className << " remove_object )";
|
|
if (writeMethodBody) {
|
|
TQString method = VECTOR_METHOD_REMOVE;
|
|
method.replace(TQRegExp("%VARNAME%"),fieldVarName);
|
|
method.replace(TQRegExp("%VECTORTYPENAME%"), policyExt()->getVectorClassName());
|
|
method.replace(TQRegExp("%ITEMCLASS%"),className);
|
|
stream << indent << " {" << m_endl;
|
|
m_indentLevel++;
|
|
printTextAsSeparateLinesWithIndent(method,getIndent(),stream);
|
|
m_indentLevel--;
|
|
stream << indent << "}" << m_endl;
|
|
} else
|
|
stream << ";" << m_endl;
|
|
}
|
|
|
|
// always allow getting the list of stuff
|
|
TQString returnVarName = policyExt()->getVectorClassName() + '<' + className + '>';
|
|
writeDocumentation("Get the list of " + fldName + " objects held by " + fieldVarName,
|
|
description,
|
|
"@return " + returnVarName + " list of " + fldName + " objects held by " + fieldVarName,
|
|
stream);
|
|
stream << indent << returnVarName << " ";
|
|
if(!isHeaderMethod)
|
|
stream << m_classifierInfo->className << "::";
|
|
stream << "get" << fldName << "List ( )";
|
|
if(writeMethodBody) {
|
|
stream << indent << " {" << m_endl;
|
|
m_indentLevel++;
|
|
stream << getIndent() << "return " << fieldVarName << ";" << m_endl;
|
|
m_indentLevel--;
|
|
stream << indent << "}" << m_endl;
|
|
} else
|
|
stream << ";" << m_endl;
|
|
|
|
}
|
|
|
|
|
|
void CppWriter::writeSingleAttributeAccessorMethods(
|
|
const TQString& fieldClassName, const TQString& fieldVarName,
|
|
const TQString& fieldName, const TQString &description,
|
|
Uml::Changeability_Type change,
|
|
bool isHeaderMethod,
|
|
bool isStatic,
|
|
bool writeMethodBody,
|
|
TQTextStream &stream)
|
|
{
|
|
|
|
// DON'T write this IF its a source method AND writeMethodBody is "false"
|
|
if(!isHeaderMethod && !writeMethodBody)
|
|
return;
|
|
|
|
TQString className = fixTypeName(fieldClassName);
|
|
TQString fldName = Codegen_Utils::capitalizeFirstLetter(fieldName);
|
|
TQString indent = getIndent();
|
|
|
|
// set method
|
|
if (change == Uml::chg_Changeable && !isStatic) {
|
|
writeDocumentation("Set the value of " + fieldVarName,description,"@param new_var the new value of " + fieldVarName,stream);
|
|
stream << indent << "void ";
|
|
if(!isHeaderMethod)
|
|
stream << m_classifierInfo->className << "::";
|
|
stream << "set" << fldName << " ( " << className << " new_var )";
|
|
|
|
if(writeMethodBody) {
|
|
stream << indent << " {" << m_endl;
|
|
m_indentLevel++;
|
|
stream << getIndent() << indent;
|
|
m_indentLevel--;
|
|
if(isStatic)
|
|
stream << m_classifierInfo->className << "::";
|
|
stream << fieldVarName << " = new_var;" << m_endl;
|
|
stream << indent << "}" << m_endl;
|
|
} else
|
|
stream << ";" << m_endl;
|
|
}
|
|
|
|
// get method
|
|
writeDocumentation("Get the value of " + fieldVarName,description,"@return the value of " + fieldVarName,stream);
|
|
stream << indent << className << " ";
|
|
if(!isHeaderMethod)
|
|
stream << m_classifierInfo->className << "::";
|
|
stream << "get" << fldName << " ( )";
|
|
|
|
if(writeMethodBody) {
|
|
stream << indent << " {" << m_endl;
|
|
m_indentLevel++;
|
|
stream << getIndent() << "return ";
|
|
m_indentLevel--;
|
|
if(isStatic)
|
|
stream << m_classifierInfo->className << "::";
|
|
stream << fieldVarName << ";" << m_endl;
|
|
stream << indent << "}";
|
|
} else
|
|
stream << ";" << m_endl;
|
|
|
|
writeBlankLine(stream);
|
|
}
|
|
|
|
// one day, this should print out non-empty constructor operations too.
|
|
void CppWriter::writeConstructorDecls(TQTextStream &stream)
|
|
{
|
|
const bool generateEmptyConstructors =
|
|
UMLApp::app()->getCommonPolicy()->getAutoGenerateConstructors();
|
|
if (forceDoc() || generateEmptyConstructors)
|
|
{
|
|
writeComment("Constructors/Destructors", getIndent(), stream);
|
|
writeComment(" ", getIndent(), stream);
|
|
writeBlankLine(stream);
|
|
}
|
|
if (!generateEmptyConstructors)
|
|
return;
|
|
|
|
writeDocumentation("", "Empty Constructor", "", stream);
|
|
stream << getIndent() << m_classifierInfo->className << " ( );" << m_endl;
|
|
writeDocumentation("", "Empty Destructor", "", stream);
|
|
stream << getIndent();
|
|
stream << "virtual ~" << m_classifierInfo->className << " ( );" << m_endl;
|
|
writeBlankLine(stream);
|
|
}
|
|
|
|
void CppWriter::writeInitAttibuteDecl (TQTextStream &stream)
|
|
{
|
|
if (UMLApp::app()->getCommonPolicy()->getAutoGenerateConstructors() &&
|
|
m_classifierInfo->hasAttributes)
|
|
stream << getIndent() << "void initAttributes ( ) ;" << m_endl;
|
|
}
|
|
|
|
void CppWriter::writeInitAttibuteMethod (TQTextStream &stream)
|
|
{
|
|
// only need to do this under certain conditions
|
|
if (!UMLApp::app()->getCommonPolicy()->getAutoGenerateConstructors() ||
|
|
!m_classifierInfo->hasAttributes)
|
|
return;
|
|
|
|
TQString className = m_classifierInfo->className;
|
|
TQString indent = getIndent();
|
|
|
|
stream << indent << "void " << className << "::" << "initAttributes ( ) {" << m_endl;
|
|
|
|
m_indentLevel++;
|
|
// first, initiation of fields derived from attributes
|
|
UMLAttributeList atl = m_classifierInfo->getAttList();
|
|
for(UMLAttribute *at = atl.first(); at ; at = atl.next()) {
|
|
if(!at->getInitialValue().isEmpty()) {
|
|
TQString varName = getAttributeVariableName(at);
|
|
stream << getIndent() << varName << " = " << at->getInitialValue() << ";" << m_endl;
|
|
}
|
|
}
|
|
// Now initialize the association related fields (e.g. vectors)
|
|
if (!VECTOR_METHOD_INIT.isEmpty()) {
|
|
TQStringList::Iterator it;
|
|
for( it = VectorFieldVariables.begin(); it != VectorFieldVariables.end(); ++it ) {
|
|
TQString fieldVarName = *it;
|
|
TQString method = VECTOR_METHOD_INIT;
|
|
method.replace(TQRegExp("%VARNAME%"),fieldVarName);
|
|
method.replace(TQRegExp("%VECTORTYPENAME%"), policyExt()->getVectorClassName());
|
|
stream << getIndent() << method << m_endl;
|
|
}
|
|
}
|
|
|
|
if (!OBJECT_METHOD_INIT.isEmpty()) {
|
|
TQStringList::Iterator it;
|
|
for( it = ObjectFieldVariables.begin(); it != ObjectFieldVariables.end(); ++it ) {
|
|
TQString fieldVarName = *it;
|
|
it++;
|
|
TQString fieldClassName = *it;
|
|
TQString method = OBJECT_METHOD_INIT;
|
|
method.replace(TQRegExp("%VARNAME%"),fieldVarName);
|
|
method.replace(TQRegExp("%ITEMCLASS%"),fieldClassName);
|
|
stream << getIndent() << method << m_endl;
|
|
}
|
|
}
|
|
|
|
// clean up
|
|
ObjectFieldVariables.clear(); // shouldn't be needed?
|
|
VectorFieldVariables.clear(); // shouldn't be needed?
|
|
|
|
m_indentLevel--;
|
|
|
|
stream << indent << "}" << m_endl;
|
|
}
|
|
|
|
// one day, this should print out non-empty constructor operations too.
|
|
void CppWriter::writeConstructorMethods(TQTextStream &stream)
|
|
{
|
|
const bool generateEmptyConstructors =
|
|
UMLApp::app()->getCommonPolicy()->getAutoGenerateConstructors();
|
|
|
|
if (forceDoc() || generateEmptyConstructors) {
|
|
writeComment("Constructors/Destructors", getIndent(), stream);
|
|
writeComment(" ", getIndent(), stream);
|
|
writeBlankLine(stream);
|
|
}
|
|
if (!generateEmptyConstructors)
|
|
return;
|
|
|
|
TQString className = m_classifierInfo->className;
|
|
// empty constructor
|
|
TQString indent = getIndent();
|
|
stream << indent << className << "::" << className << " ( ) {" << m_endl;
|
|
if(m_classifierInfo->hasAttributes)
|
|
stream << indent << indent << "initAttributes();" << m_endl;
|
|
stream << indent << "}" << m_endl;
|
|
writeBlankLine(stream);
|
|
|
|
// empty destructor
|
|
stream << getIndent() << className << "::~" << className << " ( ) { }" << m_endl;
|
|
writeBlankLine(stream);
|
|
}
|
|
|
|
// IF the type is "string" we need to declare it as
|
|
// the Java Object "String" (there is no string primative in Java).
|
|
TQString CppWriter::fixTypeName(const TQString &string)
|
|
{
|
|
if (string.isEmpty())
|
|
return "void";
|
|
if (string == "string")
|
|
return policyExt()->getStringClassName();
|
|
return string;
|
|
}
|
|
|
|
void CppWriter::writeOperations(UMLClassifier *c, bool isHeaderMethod,
|
|
Uml::Visibility permitScope, TQTextStream &cpp) {
|
|
|
|
UMLOperationList oplist;
|
|
|
|
//sort operations by scope first and see if there are abstract methods
|
|
UMLOperationList inputlist = c->getOpList();
|
|
for (UMLOperation *op = inputlist.first(); op; op = inputlist.next()) {
|
|
if (op->getVisibility() == permitScope) {
|
|
oplist.append(op);
|
|
}
|
|
}
|
|
|
|
// do people REALLY want these comments? Hmm.
|
|
/*
|
|
if(forceSections() || oppub.count())
|
|
{
|
|
writeComment("public operations",getIndent(),cpp);
|
|
writeBlankLine(cpp);
|
|
}
|
|
*/
|
|
writeOperations(oplist,isHeaderMethod, cpp);
|
|
|
|
}
|
|
|
|
// write operation in either header or
|
|
// a source file
|
|
void CppWriter::writeOperations(UMLOperationList &oplist, bool isHeaderMethod, TQTextStream &cpp) {
|
|
TQString className = m_classifierInfo->className;
|
|
const bool generateEmptyConstructors =
|
|
UMLApp::app()->getCommonPolicy()->getAutoGenerateConstructors();
|
|
|
|
// generate method decl for each operation given
|
|
for (UMLOperation *op = oplist.first(); op; op = oplist.next()) {
|
|
|
|
TQString returnStr; // buffer for documentation
|
|
TQString methodReturnType;
|
|
UMLAttributeList atl = op->getParmList(); // method parameters
|
|
|
|
if (op->isConstructorOperation()) {
|
|
if (generateEmptyConstructors && atl.count() == 0)
|
|
continue; // it's already been written, see writeConstructor{Decls,Methods}
|
|
} else if (op->isDestructorOperation()) {
|
|
if (generateEmptyConstructors)
|
|
continue; // it's already been written, see writeConstructor{Decls,Methods}
|
|
} else {
|
|
methodReturnType = fixTypeName(op->getTypeName());
|
|
if(methodReturnType != "void")
|
|
returnStr += "@return " + methodReturnType + '\n';
|
|
}
|
|
|
|
TQString str;
|
|
if (op->getAbstract() || m_classifierInfo->isInterface) {
|
|
if (isHeaderMethod) {
|
|
// declare abstract method as 'virtual'
|
|
str += "virtual ";
|
|
}
|
|
}
|
|
|
|
// static declaration for header file
|
|
if (isHeaderMethod && op->getStatic())
|
|
str += "static ";
|
|
|
|
// returntype of method
|
|
str += methodReturnType + ' ';
|
|
|
|
if (!isHeaderMethod)
|
|
str += className + "::";
|
|
|
|
str += cleanName(op->getName()) + " (";
|
|
|
|
// generate parameters
|
|
uint j = 0;
|
|
for (UMLAttribute *at = atl.first(); at; at = atl.next(), j++) {
|
|
TQString typeName = fixTypeName(at->getTypeName());
|
|
TQString atName = cleanName(at->getName());
|
|
str += typeName + ' ' + atName;
|
|
const TQString initVal = at->getInitialValue();
|
|
if (! initVal.isEmpty())
|
|
str += " = " + initVal;
|
|
if (j < atl.count() - 1)
|
|
str += ", ";
|
|
returnStr += "@param " + atName + ' ' + at->getDoc() + '\n';
|
|
}
|
|
str += " )";
|
|
|
|
if (op->getConst())
|
|
str += " const";
|
|
|
|
// method body : only gets IF its not in a header
|
|
if (isHeaderMethod && !policyExt()->getOperationsAreInline())
|
|
str += ';'; // terminate now
|
|
else
|
|
str +=getIndent() + " {\n\n" + getIndent() + '}'; // empty method body
|
|
|
|
// write it out
|
|
writeDocumentation("", op->getDoc(), returnStr, cpp);
|
|
cpp << getIndent() << str << m_endl;
|
|
writeBlankLine(cpp);
|
|
}
|
|
}
|
|
|
|
// To prevent circular including when both classifiers on either end
|
|
// of an association have roles we need to have forward declaration of
|
|
// the other class...but only IF its not THIS class (as could happen
|
|
// in self-association relationship).
|
|
void CppWriter::printAssociationIncludeDecl (UMLAssociationList list, Uml::IDType myId, TQTextStream &stream)
|
|
{
|
|
|
|
for (UMLAssociation *a = list.first(); a; a = list.next()) {
|
|
UMLClassifier *current = NULL;
|
|
bool isFirstClass = true;
|
|
|
|
// only use OTHER classes (e.g. we don't need to write includes for ourselves!!
|
|
// AND only IF the roleName is defined, otherwise, its not meant to be noticed.
|
|
if (a->getObjectId(Uml::A) == myId && !a->getRoleName(Uml::B).isEmpty()) {
|
|
current = dynamic_cast<UMLClassifier*>(a->getObject(Uml::B));
|
|
} else if (a->getObjectId(Uml::B) == myId && !a->getRoleName(Uml::A).isEmpty()) {
|
|
current = dynamic_cast<UMLClassifier*>(a->getObject(Uml::A));
|
|
isFirstClass = false;
|
|
}
|
|
|
|
// as header doc for this method indicates, we need to be a bit sophisticated on
|
|
// how to declare some associations.
|
|
if( current )
|
|
if( !isFirstClass && !a->getRoleName(Uml::A).isEmpty() && !a->getRoleName(Uml::B).isEmpty())
|
|
stream << "class " << current->getName() << ";" << m_endl; // special case: use forward declaration
|
|
else
|
|
stream << "#include \"" << current->getName() << ".h\"" << m_endl; // just the include statement
|
|
}
|
|
}
|
|
|
|
TQString CppWriter::fixInitialStringDeclValue(const TQString &value, const TQString &type)
|
|
{
|
|
TQString val = value;
|
|
// check for strings only
|
|
if (!val.isEmpty() && type == policyExt()->getStringClassName()) {
|
|
if (!val.startsWith("\""))
|
|
val.prepend("\"");
|
|
if (!val.endsWith("\""))
|
|
val.append("\"");
|
|
}
|
|
return val;
|
|
}
|
|
|
|
// methods like this _shouldn't_ be needed IF we properly did things thruought the code.
|
|
TQString CppWriter::getUMLObjectName(UMLObject *obj)
|
|
{
|
|
return(obj!=0)?obj->getName():TQString("NULL");
|
|
}
|
|
|
|
void CppWriter::writeBlankLine(TQTextStream &stream)
|
|
{
|
|
stream << m_endl;
|
|
}
|
|
|
|
void CppWriter::printTextAsSeparateLinesWithIndent (const TQString &text, const TQString &indent, TQTextStream &stream)
|
|
{
|
|
if(text.isEmpty())
|
|
return;
|
|
|
|
TQStringList lines = TQStringList::split( "\n", text);
|
|
for(uint i= 0; i < lines.count(); i++)
|
|
stream << indent << lines[i] << m_endl;
|
|
}
|
|
|
|
TQString CppWriter::getAttributeVariableName (UMLAttribute *at)
|
|
{
|
|
TQString fieldName = "m_" + cleanName(at->getName());
|
|
return fieldName;
|
|
}
|
|
|
|
TQStringList CppWriter::defaultDatatypes() {
|
|
return Codegen_Utils::cppDatatypes();
|
|
}
|
|
|
|
const TQStringList CppWriter::reservedKeywords() const {
|
|
return Codegen_Utils::reservedCppKeywords();
|
|
}
|
|
|