summaryrefslogtreecommitdiffstats
path: root/umbrello/umbrello/codegenerators/dwriter.cpp
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitbd9e6617827818fd043452c08c606f07b78014a0 (patch)
tree425bb4c3168f9c02f10150f235d2cb998dcc6108 /umbrello/umbrello/codegenerators/dwriter.cpp
downloadtdesdk-bd9e6617827818fd043452c08c606f07b78014a0.tar.gz
tdesdk-bd9e6617827818fd043452c08c606f07b78014a0.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdesdk@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'umbrello/umbrello/codegenerators/dwriter.cpp')
-rw-r--r--umbrello/umbrello/codegenerators/dwriter.cpp970
1 files changed, 970 insertions, 0 deletions
diff --git a/umbrello/umbrello/codegenerators/dwriter.cpp b/umbrello/umbrello/codegenerators/dwriter.cpp
new file mode 100644
index 00000000..3e16b136
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/dwriter.cpp
@@ -0,0 +1,970 @@
+
+/***************************************************************************
+ * *
+ * 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) 2007 Jari-Matti Mäkelä <jmjm@iki.fi> *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/***************************************************************************
+ 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.
+ ***************************************************************************/
+
+// own header
+#include "dwriter.h"
+// qt includes
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+// kde includes
+#include <kdebug.h>
+// app includes
+#include "../umldoc.h"
+#include "../classifier.h"
+#include "../operation.h"
+#include "../attribute.h"
+#include "../association.h"
+#include "../template.h"
+#include "../umltemplatelist.h"
+#include "codegen_utils.h"
+
+DWriter::DWriter() {
+ startline = m_endl + m_indentation;
+}
+
+DWriter::~DWriter() {}
+
+Uml::Programming_Language DWriter::getLanguage() {
+ return Uml::pl_D;
+}
+
+// FIXME: doesn't work yet
+void DWriter::writeModuleDecl(UMLClassifier *c, QTextStream &d) {
+ if(!c->getPackage().isEmpty())
+ d << "module " << c->getPackage() << ";" << m_endl;
+
+ writeBlankLine(d);
+}
+
+void DWriter::writeModuleImports(UMLClassifier *c, QTextStream &d) {
+ // another preparation, determine what we have
+ UMLAssociationList associations = c->getSpecificAssocs(Uml::at_Association); // BAD! only way to get "general" associations.
+ UMLAssociationList uniAssociations = c->getUniAssociationToBeImplemented();
+
+ UMLAssociationList aggregations = c->getAggregations();
+ UMLAssociationList compositions = c->getCompositions();
+
+ bool hasAssociations = aggregations.count() + associations.count() +
+ compositions.count() + uniAssociations.count() > 0;
+
+ if (hasAssociations) {
+ // import tango, if that mode is set
+ writeBlankLine(d);
+ }
+
+ //only import classes in a different package as this class
+ UMLPackageList imports;
+ findObjectsRelated(c, imports);
+ for (UMLPackage *con = imports.first(); con; con = imports.next()) {
+ if (con->getBaseType() == Uml::ot_Datatype)
+ continue;
+ QString pkg = con->getPackage();
+ if (!pkg.isEmpty() && pkg != c->getPackage())
+ d << "import " << pkg << "." << cleanName(con->getName()) << ";"
+ << m_endl;
+ }
+
+ writeBlankLine(d);
+}
+
+void DWriter::writeClass(UMLClassifier *c) {
+ if (!c) {
+ kDebug()<<"Cannot write class of NULL concept!\n";
+ return;
+ }
+
+ isInterface = c->isInterface();
+
+ QString fileName = cleanName(c->getName().lower());
+
+ //find an appropriate name for our file
+ fileName = findFileName(c, ".d");
+ if (fileName.isEmpty()) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ // check that we may open that file for writing
+ QFile file;
+ if ( !openFile(file, fileName) ) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ // open text stream to file
+ QTextStream d(&file);
+
+ //try to find a heading file (license, coments, etc)
+ QString str;
+ str = getHeadingFile(".d");
+ if(!str.isEmpty()) {
+ str.replace(QRegExp("%filename%"),fileName);
+ str.replace(QRegExp("%filepath%"),file.name());
+ d<<str<<m_endl;
+ }
+
+ // source file begins with the module declaration
+ writeModuleDecl(c, d);
+
+ // imports
+ writeModuleImports(c, d);
+
+ // write the opening declaration for the class incl any documentation,
+ // interfaces and/or inheritence issues we have
+ writeClassDecl(c, d);
+
+ // start body of class
+ d << " {" << m_endl;
+
+
+ // Preparations
+ //
+
+ // sort attributes by Scope
+ UMLAttributeList atl;
+ UMLAttributeList atpub, atprot, atpriv, atpkg, atexport;
+ UMLAttributeList final_atpub, final_atprot, final_atpriv, final_atpkg, final_atexport;
+
+ atpub.setAutoDelete(false);
+ final_atpub.setAutoDelete(false);
+ atprot.setAutoDelete(false);
+ final_atprot.setAutoDelete(false);
+ atpriv.setAutoDelete(false);
+ final_atpriv.setAutoDelete(false);
+ atpkg.setAutoDelete(false);
+ final_atpkg.setAutoDelete(false);
+ atexport.setAutoDelete(false);
+ final_atexport.setAutoDelete(false);
+
+ if (!isInterface) {
+ UMLAttributeList atl = c->getAttributeList();
+ for (UMLAttribute *at = atl.first(); at ; at = atl.next()) {
+ switch(at->getVisibility())
+ {
+ case Uml::Visibility::Public:
+ if(at->getStatic())
+ final_atpub.append(at);
+ else
+ atpub.append(at);
+ break;
+ case Uml::Visibility::Protected:
+ if(at->getStatic())
+ final_atprot.append(at);
+ else
+ atprot.append(at);
+ break;
+ case Uml::Visibility::Private:
+ if(at->getStatic())
+ final_atpriv.append(at);
+ else
+ atpriv.append(at);
+ break;/* TODO: requires support from the gui & other structures
+ case Uml::Visibility::Package:
+ if(at->getStatic())
+ final_atpkg.append(at);
+ else
+ atpkg.append(at);
+ break;
+ case Uml::Visibility::Export:
+ if(at->getStatic())
+ final_atexport.append(at);
+ else
+ atexport.append(at);
+ break;*/
+ default:
+ break;
+ }
+ }
+ }
+
+ // another preparation, determine what we have
+ UMLAssociationList associations = c->getSpecificAssocs(Uml::at_Association); // BAD! only way to get "general" associations.
+ UMLAssociationList uniAssociations = c->getUniAssociationToBeImplemented();
+
+ UMLAssociationList aggregations = c->getAggregations();
+ UMLAssociationList compositions = c->getCompositions();
+
+ bool hasAssociations = aggregations.count() + associations.count() + compositions.count() + uniAssociations.count() > 0;
+ bool hasAttributes = atl.count() > 0;
+ bool hasAccessorMethods = hasAttributes || hasAssociations;
+ bool hasOperationMethods = c->getOpList().count() > 0;
+
+ // ATTRIBUTES
+ //
+
+ // write comment for section IF needed
+ if (forceDoc() || hasAccessorMethods)
+ {
+ writeComment("", m_indentation, d);
+ writeComment("Fields", m_indentation, d);
+ writeComment("", m_indentation, d);
+ writeBlankLine(d);
+ }
+
+ writeAttributeDecls(final_atpub, final_atprot, final_atpriv, d);
+ writeAttributeDecls(atpub, atprot, atpriv, d);
+
+ writeAssociationDecls(associations, c->getID(), d);
+ writeAssociationDecls(uniAssociations, c->getID(), d);
+ writeAssociationDecls(aggregations, c->getID(), d);
+ writeAssociationDecls(compositions, c->getID(), d);
+
+ //FIXME: find constructors and write them here
+
+ // write constructors
+ if(!isInterface) writeConstructor(c, d);
+
+
+ // METHODS
+ //
+
+ // write comment for sub-section IF needed
+ if (forceDoc() || hasAccessorMethods ) {
+ writeComment("", m_indentation, d);
+ writeComment("Accessors", m_indentation, d);
+ writeComment("", m_indentation, d);
+ writeBlankLine(d);
+ }
+
+
+ // Accessors for attributes
+ writeAttributeMethods(final_atpub, Uml::Visibility::Public, d);
+ writeAttributeMethods(final_atprot, Uml::Visibility::Protected, d);
+ writeAttributeMethods(final_atpriv, Uml::Visibility::Private, d);
+ writeAttributeMethods(atpub, Uml::Visibility::Public, d);
+ writeAttributeMethods(atprot, Uml::Visibility::Protected, d);
+ writeAttributeMethods(atpriv, Uml::Visibility::Private, d);
+
+ // accessor methods for associations
+
+ // first: determine the name of the other class
+ writeAssociationMethods(associations, c, d);
+ writeAssociationMethods(uniAssociations, c, d);
+ writeAssociationMethods(aggregations, c, d);
+ writeAssociationMethods(compositions, c, d);
+
+ // Other operation methods
+ // all other operations are now written
+
+ // write comment for sub-section IF needed
+ if (forceDoc() || hasOperationMethods) {
+ writeComment("", m_indentation, d);
+ writeComment("Other methods", m_indentation, d);
+ writeComment("", m_indentation, d);
+ writeBlankLine(d);
+ }
+
+ writeOperations(c, d);
+
+ d << "}" << m_endl; // end class
+
+ file.close();
+ emit codeGenerated(c, true);
+}
+
+void DWriter::writeClassDecl(UMLClassifier *c, QTextStream &d) {
+
+ // class documentation
+ if (!c->getDoc().isEmpty()) {
+ writeDocumentation("", c->getDoc(), "", "", d);
+ }
+
+ /*
+ * Class declaration
+ *
+ * (private) class foo(T, ..., Z) : class1, ..., classN, interface1, ..., interfaceN
+ * a b c d e f g
+ */
+
+ // (a) visibility modifier
+ switch(c->getVisibility()) {
+ case Uml::Visibility::Private: d << "private "; break;
+ default: break;
+ }
+
+ // (b) keyword
+ // TODO what about structs?
+ if (isInterface) {
+ d << "interface ";
+ } else {
+ if (c->getAbstract()) {
+ d << "abstract ";
+ }
+
+ d << "class ";
+ }
+
+ // (c) class name
+ QString classname = cleanName(c->getName()); // our class name
+ d << classname;
+
+ // (d) template parameters
+ UMLTemplateList template_params = c->getTemplateList();
+ if (template_params.count()) {
+ d << "(";
+
+ for (UMLTemplate *t = template_params.first(); t; ) {
+ // TODO: hm, leaving the type blank results in "class"
+ // so we omit it (also because "class" in this context is illegal)
+ if (t->getTypeName() != "class") {
+ d << t->getTypeName();
+ d << " ";
+ }
+
+ d << t->getName();
+
+ if ((t = template_params.next()) != NULL)
+ d << ", ";
+ }
+
+ d << ")";
+ }
+
+ // (e) inheritances
+ UMLClassifierList superclasses =
+ c->findSuperClassConcepts(UMLClassifier::CLASS);
+ UMLClassifierList superinterfaces =
+ c->findSuperClassConcepts(UMLClassifier::INTERFACE);
+
+ int count = superclasses.count() + superinterfaces.count();
+
+ if (count > 0) {
+ d << " : ";
+
+ // (f) base classes
+ for (UMLClassifier * concept= superclasses.first(); concept; concept = superclasses.next()) {
+ d << cleanName(concept->getName());
+
+ count--;
+
+ if (count>0) d << ", ";
+ }
+
+ // (g) interfaces
+ for (UMLClassifier * concept= superinterfaces.first(); concept; concept = superinterfaces.next()) {
+ d << cleanName(concept->getName());
+
+ count--;
+
+ if (count>0) d << ", ";
+ }
+ }
+}
+
+void DWriter::writeProtectionMod(Uml::Visibility visibility, QTextStream &d) {
+ d << m_indentation << scopeToDDecl(visibility) << ":" << m_endl << m_endl;
+}
+
+void DWriter::writeAttributeDecl(Uml::Visibility visibility, UMLAttributeList &atlist, QTextStream &d) {
+ if (atlist.count()==0) return;
+
+ writeProtectionMod(visibility, d);
+
+ for(UMLAttribute *at=atlist.first(); at; at=atlist.next()) {
+ // documentation
+ if (!at->getDoc().isEmpty()) {
+ writeComment(at->getDoc(), m_indentation, d, true);
+ }
+
+ d << m_indentation;
+
+ // static attribute?
+ if (at->getStatic()) d << "static ";
+
+ // method return type
+ d << fixTypeName(at->getTypeName()) << " ";
+
+ // TODO: find out whether this class has accessors or not
+ bool hasAccessorMethods = true;
+
+ // attribute name
+ if (hasAccessorMethods) {
+ d << "m_";
+ }
+ d << cleanName(at->getName());
+
+ // initial value
+ QString initVal = fixInitialStringDeclValue(at->getInitialValue(), at->getTypeName());
+ if (!initVal.isEmpty()) d << " = " << initVal;
+ d << ";" << m_endl << m_endl;
+ }
+}
+
+void DWriter::writeAttributeDecls(UMLAttributeList &atpub, UMLAttributeList &atprot,
+ UMLAttributeList &atpriv, QTextStream &d ) {
+
+ writeAttributeDecl(Uml::Visibility::Public, atpub, d);
+ writeAttributeDecl(Uml::Visibility::Protected, atprot, d);
+ writeAttributeDecl(Uml::Visibility::Private, atpriv, d);
+ //TODO: export and package
+}
+
+void DWriter::writeAttributeMethods(UMLAttributeList &atpub, Uml::Visibility visibility, QTextStream &d) {
+ if (atpub.count()==0) return;
+
+ writeProtectionMod(visibility, d);
+
+ for(UMLAttribute *at=atpub.first(); at; at=atpub.next()) {
+ QString fieldName = cleanName(at->getName());
+ writeSingleAttributeAccessorMethods(
+ at->getTypeName(), "m_" + fieldName, fieldName, at->getDoc(),
+ visibility, Uml::chg_Changeable, at->getStatic(), d);
+ }
+}
+
+void DWriter::writeComment(const QString &comment, const QString &myIndent,
+ QTextStream &d, bool dDocStyle) {
+ if(dDocStyle) {
+ d << myIndent << "/**" << m_endl;
+ }
+
+ QStringList lines = QStringList::split("\n", comment);
+
+ if (lines.count() == 0) lines << comment;
+
+ for (uint i = 0; i < lines.count(); ++i) {
+ QString tmp = lines[i];
+
+ while (tmp.length() > 77) {
+ uint l = tmp.left(77).findRev(' ');
+ if (l < 1) l = tmp.find(' ', 77);
+ if (l < 1 || l > tmp.length()) {
+ d << myIndent << (dDocStyle ? " * " : "// ") << tmp << m_endl;
+ break;
+ }
+ d << myIndent << (dDocStyle ? " * " : "// ") << tmp.left(l) << m_endl;
+ tmp = tmp.right(tmp.length() - l);
+ }
+
+ d << myIndent << (dDocStyle ? " * " : "// ") << tmp << m_endl;
+ }
+
+ if(dDocStyle) {
+ d << myIndent << " */" << m_endl;
+ }
+}
+
+void DWriter::writeDocumentation(QString header, QString body, QString end, QString indent, QTextStream &d) {
+ d << indent << "/**" << m_endl;
+ if (!header.isEmpty())
+ d << formatDoc(header, indent+" * ");
+ if (!body.isEmpty())
+ d << formatDoc(body, indent+" * ");
+ if (!end.isEmpty())
+ {
+ QStringList lines = QStringList::split( "\n", end);
+ for (uint i= 0; i < lines.count(); i++)
+ d << formatDoc(lines[i], indent + " * ");
+ }
+ d<<indent<< " */" << m_endl;
+}
+
+void DWriter::writeAssociationDecls(UMLAssociationList associations, Uml::IDType id, QTextStream &d) {
+
+ 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)
+ printRoleB = true;
+
+ if (a->getObjectId(Uml::B) == id)
+ 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(), m_indentation, d);
+
+ // print RoleB decl
+ if (printRoleB)
+ {
+ QString fieldClassName = cleanName(getUMLObjectName(a->getObject(Uml::B)));
+ writeAssociationRoleDecl(fieldClassName, a->getRoleName(Uml::B), a->getMulti(Uml::B), a->getRoleDoc(Uml::B), a->getVisibility(Uml::B), d);
+ }
+
+ // print RoleA decl
+ if (printRoleA)
+ {
+ QString fieldClassName = cleanName(getUMLObjectName(a->getObject(Uml::A)));
+ writeAssociationRoleDecl(fieldClassName, a->getRoleName(Uml::A), a->getMulti(Uml::A), a->getRoleDoc(Uml::A), a->getVisibility(Uml::A), d);
+ }
+ }
+ }
+}
+
+void DWriter::writeAssociationRoleDecl(QString fieldClassName,
+ QString roleName, QString multi,
+ QString doc, Uml::Visibility /*visib*/, QTextStream &d) {
+ // ONLY write out IF there is a rolename given
+ // otherwise its not meant to be declared in the code
+ if (roleName.isEmpty()) return;
+
+ if (!doc.isEmpty()) {
+ writeComment(doc, m_indentation, d);
+ }
+
+ bool hasAccessors = true;
+
+ // 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(QRegExp("^[01]$"))) {
+ d << m_indentation << fieldClassName << " ";
+
+ if (hasAccessors) d << "m_";
+
+ d << deCapitaliseFirstLetter(roleName) << ";";
+ } else {
+ d << m_indentation << fieldClassName << "[] ";
+ //TODO: templated containers
+
+ if (hasAccessors) d << "m_";
+
+ d << pluralize(deCapitaliseFirstLetter(roleName)) << ";";
+ // from here we could initialize default values, or put in an init() section
+ // of the constructors
+ }
+
+ // always put space between this and following decl, if any
+ writeBlankLine(d);
+}
+
+void DWriter::writeAssociationMethods (UMLAssociationList associations, UMLClassifier *thisClass, QTextStream &d) {
+ 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) == thisClass->getID()) {
+ // only write out IF there is a rolename given
+ if(!a->getRoleName(Uml::B).isEmpty()) {
+ QString fieldClassName = getUMLObjectName(a->getObject(Uml::B));
+ writeAssociationRoleMethod(fieldClassName,
+ a->getRoleName(Uml::B),
+ a->getMulti(Uml::B), a->getRoleDoc(Uml::B),
+ a->getVisibility(Uml::B),
+ a->getChangeability(Uml::B), d);
+ }
+ }
+
+ if (a->getObjectId(Uml::B) == thisClass->getID()) {
+ // only write out IF there is a rolename given
+ if(!a->getRoleName(Uml::A).isEmpty()) {
+ QString fieldClassName = getUMLObjectName(a->getObject(Uml::A));
+ writeAssociationRoleMethod(fieldClassName, a->getRoleName(Uml::A),
+ a->getMulti(Uml::A),
+ a->getRoleDoc(Uml::A),
+ a->getVisibility(Uml::A),
+ a->getChangeability(Uml::A),
+ d);
+ }
+ }
+ }
+ }
+}
+
+void DWriter::writeAssociationRoleMethod (QString fieldClassName, QString roleName, QString multi,
+ QString description, Uml::Visibility visib, Uml::Changeability_Type change,
+ QTextStream &d) {
+ if(multi.isEmpty() || multi.contains(QRegExp("^[01]$"))) {
+ QString fieldVarName = "m_" + deCapitaliseFirstLetter(roleName);
+
+ writeSingleAttributeAccessorMethods(
+ fieldClassName, fieldVarName, roleName, description, visib, change, false, d);
+ } else {
+ QString fieldVarName = "m_" + pluralize(deCapitaliseFirstLetter(roleName));
+
+ writeVectorAttributeAccessorMethods(
+ fieldClassName, fieldVarName, pluralize(roleName), description, visib, change, d);
+ }
+}
+
+void DWriter::writeVectorAttributeAccessorMethods (QString fieldClassName, QString fieldVarName,
+ QString fieldName, QString description,
+ Uml::Visibility /*visibility*/, Uml::Changeability_Type changeType,
+ QTextStream &d) {
+
+ fieldClassName = fixTypeName(fieldClassName);
+ QString fieldNameUP = unPluralize(fieldName);
+ QString fieldNameUC = Codegen_Utils::capitalizeFirstLetter(fieldNameUP);
+
+ // ONLY IF changeability is NOT Frozen
+ if (changeType != Uml::chg_Frozen) {
+ writeDocumentation("Adds a " + fieldNameUP + " to the list of " +
+ fieldName + '.', description, "", m_indentation, d);
+
+ d << m_indentation << "void add" << fieldNameUC << "(";
+ d << fieldClassName << " new" << fieldNameUC << ") {";
+ d << startline << m_indentation << fieldVarName << " ~= new" << fieldNameUC << ";";
+ d << startline << "}" << m_endl << m_endl;
+ }
+
+ // ONLY IF changeability is Changeable
+ if (changeType == Uml::chg_Changeable) {
+ writeDocumentation("Removes a " + fieldNameUP + " from the list of " +
+ fieldName + '.', description, "", m_indentation, d);
+
+ d << m_indentation << "void remove" << fieldNameUC << "(";
+ d << fieldClassName << " " << fieldNameUP << ") {" << startline;
+ d << m_indentation << "int idx = " << fieldVarName << ".length;" << startline;
+ d << m_indentation << "foreach(i, o; " << fieldVarName << ")" << startline;
+ d << m_indentation << m_indentation << "if (o && o == " << fieldNameUP << ") {" << startline;
+ d << m_indentation << m_indentation << m_indentation << "idx = i;" << startline;
+ d << m_indentation << m_indentation << m_indentation << "break;" << startline;
+ d << m_indentation << m_indentation << "}" << m_endl << startline;
+ d << m_indentation << fieldVarName << " = " << fieldVarName;
+ d << "[0..idx] ~ " << fieldVarName << "[idx..$];" << startline;
+ d << "}" << m_endl << m_endl;
+ }
+
+ // always allow getting the list of stuff
+ writeDocumentation("Returns the list of " + fieldName + '.',
+ description, "@return List of " + fieldName + '.',
+ m_indentation, d);
+
+ d << m_indentation << fieldClassName << "[] get" << fieldName << "() {";
+ d << startline << m_indentation << "return " << fieldVarName << ";";
+ d << startline << "}" << m_endl << m_endl;
+}
+
+
+void DWriter::writeSingleAttributeAccessorMethods(QString fieldClassName,
+ QString fieldVarName, QString fieldName, QString description, Uml::Visibility /*visibility*/,
+ Uml::Changeability_Type change, bool isFinal, QTextStream &d) {
+
+ fieldClassName = fixTypeName(fieldClassName);
+ QString fieldNameUC = Codegen_Utils::capitalizeFirstLetter(fieldName);
+ if (fieldName.left(2) == "m_") fieldName = fieldName.right(fieldName.length()-2);
+
+ // set method
+ if (change == Uml::chg_Changeable && !isFinal) {
+ writeDocumentation("Sets the value of " + fieldName + '.', description,
+ "@param new" + fieldNameUC + " The new value of " + fieldName + '.',
+ m_indentation, d);
+
+ d << m_indentation << fieldClassName << " " << fieldName << "(";
+ d << fieldClassName << " new" << fieldNameUC << ") {";
+ d << startline << m_indentation << "return " << fieldVarName << " = new" << fieldNameUC << ";";
+ d << startline << "}" << m_endl << m_endl;
+ }
+
+ // get method
+ writeDocumentation("Returns the value of " + fieldName + '.', description,
+ "@return The value of " + fieldName + '.',
+ m_indentation, d);
+
+ d << m_indentation << fieldClassName << " " << fieldName << "() {";
+ d << startline << m_indentation << "return " << fieldVarName << ";";
+ d << startline << "}" << m_endl << m_endl;
+}
+
+void DWriter::writeConstructor(UMLClassifier *c, QTextStream &d) {
+
+ if (forceDoc())
+ {
+ d<<startline;
+ writeComment("", m_indentation, d);
+ writeComment("Constructors", m_indentation, d);
+ writeComment("", m_indentation, d);
+ writeBlankLine(d);
+ }
+
+ // write the first constructor
+ QString className = cleanName(c->getName());
+ d << m_indentation << "public this("<<") { }";
+
+}
+
+// IF the type is "string" we need to declare it as
+// the D Object "String" (there is no string primative in D).
+// Same thing again for "bool" to "boolean"
+QString DWriter::fixTypeName(const QString& string) {
+ if (string.isEmpty())
+ return "void";
+ if (string == "string")
+ return "char[]";
+ if (string == "unsigned short")
+ return "ushort";
+ if (string == "unsigned int")
+ return "uint";
+ if (string == "unsigned long")
+ return "ulong";
+ return string;
+}
+
+QStringList DWriter::defaultDatatypes() {
+ QStringList l;
+ l << "void"
+ << "bool"
+ << "byte"
+ << "ubyte"
+ << "short"
+ << "ushort"
+ << "int"
+ << "uint"
+ << "long"
+ << "ulong"
+ << "cent"
+ << "ucent"
+ << "float"
+ << "double"
+ << "real"
+ << "ifloat"
+ << "idouble"
+ << "ireal"
+ << "cfloat"
+ << "cdouble"
+ << "creal"
+ << "char"
+ << "wchar"
+ << "dchar";
+ return l;
+}
+
+
+bool DWriter::compareDMethod(UMLOperation *op1, UMLOperation *op2) {
+ if (op1 == NULL || op2 == NULL)
+ return false;
+ if (op1 == op2)
+ return true;
+ if (op1->getName() != op2->getName())
+ return false;
+ UMLAttributeList atl1 = op1->getParmList();
+ UMLAttributeList atl2 = op2->getParmList();
+ if (atl1.count() != atl2.count())
+ return false;
+ UMLAttribute *at1;
+ UMLAttribute *at2;
+ for (at1 = atl1.first(), at2 = atl2.first(); at1 && at2 ; at1 = atl1.next(),at2 = atl2.next())
+ {
+ if (at1->getTypeName() != at2->getTypeName())
+ return false;
+ }
+ return true;
+
+}
+
+bool DWriter::dMethodInList(UMLOperation *umlOp, UMLOperationList &opl) {
+ for (UMLOperation *op = opl.first(); op; op = opl.next()) {
+ if (DWriter::compareDMethod(op, umlOp)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void DWriter::getSuperImplementedOperations(UMLClassifier *c, UMLOperationList &yetImplementedOpList ,UMLOperationList &toBeImplementedOpList, bool noClassInPath) {
+ UMLClassifierList superClasses = c->findSuperClassConcepts();
+
+ for (UMLClassifier *concept= superClasses.first(); concept; concept = superClasses.next())
+ {
+ getSuperImplementedOperations(concept, yetImplementedOpList, toBeImplementedOpList, (concept->isInterface() && noClassInPath));
+ UMLOperationList opl = concept->getOpList();
+ for (UMLOperation *op = opl.first(); op; op = opl.next()) {
+ if (concept->isInterface() && noClassInPath) {
+ if (!DWriter::dMethodInList(op,toBeImplementedOpList))
+ toBeImplementedOpList.append(op);
+ }
+ else
+ {
+ if (!DWriter::dMethodInList(op, yetImplementedOpList))
+ yetImplementedOpList.append(op);
+ }
+ }
+ }
+
+}
+
+void DWriter::getInterfacesOperationsToBeImplemented(UMLClassifier *c, UMLOperationList &opList ) {
+ UMLOperationList yetImplementedOpList;
+ UMLOperationList toBeImplementedOpList;
+
+ getSuperImplementedOperations(c,yetImplementedOpList, toBeImplementedOpList);
+ for (UMLOperation *op = toBeImplementedOpList.first(); op; op = toBeImplementedOpList.next())
+ {
+ if ( ! DWriter::dMethodInList(op, yetImplementedOpList) && ! DWriter::dMethodInList(op, opList) )
+ opList.append(op);
+ }
+}
+
+void DWriter::writeOperations(UMLClassifier *c, QTextStream &d) {
+ UMLOperationList opl;
+ UMLOperationList oppub,opprot,oppriv;
+ oppub.setAutoDelete(false);
+ opprot.setAutoDelete(false);
+ oppriv.setAutoDelete(false);
+
+ //sort operations by scope first and see if there are abstract methods
+ opl = c->getOpList();
+ if (! c->isInterface()) {
+ getInterfacesOperationsToBeImplemented(c, opl);
+ }
+ for (UMLOperation *op = opl.first(); op; op = opl.next()) {
+ switch(op->getVisibility()) {
+ case Uml::Visibility::Public:
+ oppub.append(op);
+ break;
+ case Uml::Visibility::Protected:
+ opprot.append(op);
+ break;
+ case Uml::Visibility::Private:
+ oppriv.append(op);
+ break;
+ default: //TODO: package, export
+ break;
+ }
+ }
+
+ // do people REALLY want these comments? Hmm.
+ /*
+ if(forceSections() || oppub.count())
+ {
+ writeComment("public operations",m_indentation,d);
+ writeBlankLine(d);
+ }
+ */
+
+ if (oppub.count() > 0) {
+ writeProtectionMod(Uml::Visibility::Public, d);
+
+ writeOperations(oppub,d);
+ }
+
+ if (opprot.count() > 0) {
+ writeProtectionMod(Uml::Visibility::Protected, d);
+
+ writeOperations(opprot, d);
+ }
+
+ if (oppriv.count() > 0) {
+ writeProtectionMod(Uml::Visibility::Private, d);
+
+ writeOperations(oppriv, d);
+ }
+
+}
+
+void DWriter::writeOperations(UMLOperationList &oplist, QTextStream &d) {
+ UMLAttributeList atl;
+ QString str;
+
+ // generate method decl for each operation given
+ for(UMLOperation *op=oplist.first(); op; op=oplist.next()) {
+ QString returnStr = "";
+ // write documentation
+
+ QString methodReturnType = fixTypeName(op->getTypeName());
+
+ //TODO: return type comment
+ if(methodReturnType != "void") {
+ returnStr += "@return " + methodReturnType + m_endl;
+ }
+
+ str = ""; // reset for next method
+ if (op->getAbstract() && !isInterface) str += "abstract ";
+ if (op->getStatic()) str += "static ";
+
+ str += methodReturnType + ' ' +cleanName(op->getName()) + '(';
+
+ atl = op->getParmList();
+ int i = atl.count();
+ int j = 0;
+ for (UMLAttribute *at = atl.first(); at; at = atl.next(), j++) {
+ QString typeName = fixTypeName(at->getTypeName());
+ QString atName = cleanName(at->getName());
+ str += typeName + ' ' + atName +
+ (!(at->getInitialValue().isEmpty()) ?
+ (QString(" = ")+at->getInitialValue()) :
+ QString(""))
+ + ((j < i-1)?", ":"");
+ returnStr += "@param " + atName+' '+at->getDoc() + m_endl;
+ }
+
+ str+= ')';
+
+ // method only gets a body IF its not abstract
+ if (op->getAbstract() || isInterface)
+ str += ';'; // terminate now
+ else
+ str += startline + '{' + startline + '}'; // empty method body
+
+ // write it out
+ writeDocumentation("", op->getDoc(), returnStr, m_indentation, d);
+ d << m_indentation << str << m_endl << m_endl;
+ }
+}
+
+QString DWriter::fixInitialStringDeclValue(QString value, QString type) {
+ // check for strings only
+ if (!value.isEmpty() && type == "String") {
+ if (!value.startsWith("\""))
+ value.prepend("\"");
+ if (!value.endsWith("\""))
+ value.append("\"");
+ }
+ return value;
+}
+
+QString DWriter::scopeToDDecl(Uml::Visibility scope) {
+ QString scopeString;
+
+ switch(scope) {
+ case Uml::Visibility::Public: scopeString = "public"; break;
+ case Uml::Visibility::Protected: scopeString = "protected"; break;
+ case Uml::Visibility::Private: scopeString = "private"; break;
+ default: break; //TODO: package and export
+ }
+
+ return scopeString;
+}
+
+// methods like this _shouldn't_ be needed IF we properly did things thruought the code.
+QString DWriter::getUMLObjectName(UMLObject *obj) {
+ return(obj!=0)?obj->getName():QString("NULL");
+}
+
+QString DWriter::deCapitaliseFirstLetter(QString string) {
+ string.replace( 0, 1, string[0].lower());
+ return string;
+}
+
+QString DWriter::pluralize(QString string) {
+ return string + (string.right(1) == "s" ? "es" : "s");
+}
+
+QString DWriter::unPluralize(QString string) {
+ // does not handle special cases liek datum -> data, etc.
+
+ if (string.length() > 2 && string.right(3) == "ses") {
+ return string.left(string.length() - 2);
+ }
+
+ if (string.right(1) == "s") {
+ return string.left(string.length() - 1);
+ }
+
+ return string;
+}
+
+void DWriter::writeBlankLine(QTextStream &d) {
+ d << m_endl;
+}
+