umbrello API Documentation

idlwriter.cpp

00001 /***************************************************************************
00002  *  copyright (C) 2003-2005                                                *
00003  *  Umbrello UML Modeller Authors <uml-devel@uml.sf.net>                   *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  ***************************************************************************/
00011 
00012 #include "idlwriter.h"
00013 
00014 #include <kdebug.h>
00015 #include <kmessagebox.h>
00016 #include <qfile.h>
00017 #include <qregexp.h>
00018 #include <qtextstream.h>
00019 
00020 #include "../umldoc.h"
00021 #include "../classifier.h"
00022 #include "../enum.h"
00023 #include "../classifierlistitem.h"
00024 #include "../umlclassifierlistitemlist.h"
00025 #include "../package.h"
00026 #include "../association.h"
00027 #include "../attribute.h"
00028 #include "../operation.h"
00029 #include "../umlnamespace.h"
00030 
00031 IDLWriter::IDLWriter() : SimpleCodeGenerator(false) {
00032 }
00033 
00034 IDLWriter::~IDLWriter() {}
00035 
00036 bool IDLWriter::isOOClass(UMLClassifier *c) {
00037     QString stype = c->getStereotype();
00038     if (stype == "CORBAConstant" || stype == "CORBAEnum" ||
00039             stype == "CORBAStruct" || stype == "CORBAUnion" ||
00040             stype == "CORBASequence" || stype == "CORBAArray" ||
00041             stype == "CORBATypedef")
00042         return false;
00043 
00044     // CORBAValue, CORBAInterface, and all empty/unknown stereotypes are
00045     // assumed to be OO classes.
00046     return true;
00047 }
00048 
00049 bool IDLWriter::assocTypeIsMappableToAttribute(Uml::Association_Type at) {
00050     return (at == Uml::at_Aggregation || at == Uml::at_Association ||
00051             at == Uml::at_Composition || at == Uml::at_UniAssociation);
00052 }
00053 
00057 Uml::Programming_Language IDLWriter::getLanguage() {
00058     return Uml::pl_IDL;
00059 }
00060 
00061 void IDLWriter::computeAssocTypeAndRole
00062 (UMLAssociation *a, UMLClassifier *c, QString& typeName, QString& roleName)
00063 {
00064     // Determine which is the "remote" end of the association:
00065     bool IAmRoleA = true;
00066     UMLObject *other = a->getObject(Uml::B);
00067     Uml::Association_Type at = a->getAssocType();
00068     if (c->getName() == other->getName()) {
00069         if (at == Uml::at_Aggregation || at == Uml::at_Composition ||
00070                 at == Uml::at_UniAssociation) {
00071             // Assuming unidirectional association, and we are
00072             // at the "wrong" side.
00073             // Returning roleName = QString::null tells caller to
00074             // skip this association at this side.
00075             roleName = QString();
00076             return;
00077         }
00078         IAmRoleA = false;
00079         other = a->getObject(Uml::A);
00080     }
00081     // Construct the type name:
00082     typeName = cleanName(other->getName());
00083     QString multiplicity;
00084     if (IAmRoleA)
00085         multiplicity = a->getMulti(Uml::B);
00086     else
00087         multiplicity = a->getMulti(Uml::A);
00088     if (!multiplicity.isEmpty() && multiplicity != "1")
00089         typeName.append("Vector");
00090     // Construct the member name:
00091     if (IAmRoleA)
00092         roleName = a->getRoleName(Uml::B);
00093     else
00094         roleName = a->getRoleName(Uml::A);
00095     if (roleName.isEmpty()) {
00096         roleName = a->getName();
00097         if (roleName.isEmpty()) {
00098             roleName = "m_" + typeName;
00099         }
00100     }
00101 }
00102 
00103 void IDLWriter::writeClass(UMLClassifier *c) {
00104     if (!c) {
00105         kDebug() << "Cannot write class of NULL concept!" << endl;
00106         return;
00107     }
00108 
00109     const bool isClass = !c->isInterface();
00110     QString classname = cleanName(c->getName());
00111 
00112     //find an appropriate name for our file
00113     QString fileName = findFileName(c, ".idl");
00114     if (fileName.isEmpty()) {
00115         emit codeGenerated(c, false);
00116         return;
00117     }
00118 
00119     QFile file;
00120     if (!openFile(file, fileName)) {
00121         emit codeGenerated(c, false);
00122         return;
00123     }
00124 
00125     // Start generating the code.
00126 
00127     QTextStream idl(&file);
00128     //try to find a heading file(license, comments, etc)
00129     QString str;
00130     str = getHeadingFile(".idl");
00131     if (!str.isEmpty()) {
00132         str.replace(QRegExp("%filename%"), fileName);
00133         str.replace(QRegExp("%filepath%"), file.name());
00134         idl << str << m_endl;
00135     }
00136 
00137     // Write includes.
00138     UMLPackageList includes;
00139     findObjectsRelated(c, includes);
00140     if (includes.count()) {
00141         for (UMLPackage *conc = includes.first(); conc; conc = includes.next()) {
00142             if (conc->getBaseType() == Uml::ot_Datatype)
00143                 continue;
00144             QString incName = findFileName(conc, ".idl");
00145             if (!incName.isEmpty())
00146                 idl << "#include \"" << incName << "\"" << m_endl;
00147         }
00148         idl << m_endl;
00149     }
00150 
00151     // Generate the module declaration(s) for the package(s) in which
00152     // we are embedded.
00153     UMLPackageList pkgList = c->getPackages();
00154     UMLPackage *pkg;
00155     for (pkg = pkgList.first(); pkg != NULL; pkg = pkgList.next()) {
00156         idl << getIndent() << "module " << pkg->getName() << " {" << m_endl << m_endl;
00157         m_indentLevel++;
00158     }
00159 
00160     // Write class Documentation if non-empty or if force option set.
00161     if (forceDoc() || !c->getDoc().isEmpty()) {
00162         idl << "//" << m_endl;
00163         idl << "// class " << classname << m_endl;
00164         idl << formatDoc(c->getDoc(), "// ");
00165         idl << m_endl;
00166     }
00167 
00168     if (c->getBaseType() == Uml::ot_Enum) {
00169         UMLClassifierListItemList litList = c->getFilteredList(Uml::ot_EnumLiteral);
00170         uint i = 0;
00171         idl << getIndent() << "enum " << classname << " {" << m_endl;
00172         m_indentLevel++;
00173         for (UMLClassifierListItem *lit = litList.first(); lit; lit = litList.next()) {
00174             QString enumLiteral = cleanName(lit->getName());
00175             idl << getIndent() << enumLiteral;
00176             if (++i < litList.count())
00177                 idl << ",";
00178             idl << m_endl;
00179         }
00180         m_indentLevel--;
00181         idl << getIndent() << "};" << m_endl << m_endl;
00182         // Close the modules inside which we might be nested.
00183         for (pkg = pkgList.first(); pkg != NULL; pkg = pkgList.next()) {
00184             m_indentLevel--;
00185             idl << getIndent() << "};" << m_endl << m_endl;
00186         }
00187         return;
00188     }
00189     if (! isOOClass(c)) {
00190         QString stype = c->getStereotype();
00191         if (stype == "CORBAConstant") {
00192             kError() << "The stereotype " << stype << " cannot be applied to "
00193             << c->getName() << ", but only to attributes." << endl;
00194             return;
00195         }
00196         if (!isClass) {
00197             kError() << "The stereotype " << stype
00198             << " cannot be applied to " << c->getName()
00199             << ", but only to classes." << endl;
00200             return;
00201         }
00202         if (stype == "CORBAEnum") {
00203             UMLAttributeList atl = c->getAttributeList();
00204             UMLAttribute *at;
00205             idl << getIndent() << "enum " << classname << " {" << m_endl;
00206             m_indentLevel++;
00207             uint i = 0;
00208             for (at = atl.first(); at; at = atl.next()) {
00209                 QString enumLiteral = cleanName(at->getName());
00210                 idl << getIndent() << enumLiteral;
00211                 if (++i < atl.count())
00212                     idl << ",";
00213                 idl << m_endl;
00214             }
00215             m_indentLevel--;
00216             idl << getIndent() << "};" << m_endl << m_endl;
00217         } else if (stype == "CORBAStruct") {
00218             UMLAttributeList atl = c->getAttributeList();
00219             UMLAttribute *at;
00220             idl << getIndent() << "struct " << classname << " {" << m_endl;
00221             m_indentLevel++;
00222             for (at = atl.first(); at; at = atl.next()) {
00223                 QString name = cleanName(at->getName());
00224                 idl << getIndent() << at->getTypeName() << " " << name << ";" << m_endl;
00225                 // Initial value not possible in IDL.
00226             }
00227             UMLAssociationList compositions = c->getCompositions();
00228             if (!compositions.isEmpty()) {
00229                 idl << getIndent() << "// Compositions." << m_endl;
00230                 for (UMLAssociation *a = compositions.first(); a; a = compositions.next()) {
00231                     QString memberType, memberName;
00232                     computeAssocTypeAndRole(a, c, memberType, memberName);
00233                     idl << getIndent() << memberType << " " << memberName << ";" << m_endl;
00234                 }
00235             }
00236             UMLAssociationList aggregations = c->getAggregations();
00237             if (!aggregations.isEmpty()) {
00238                 idl << getIndent() << "// Aggregations." << m_endl;
00239                 for (UMLAssociation *a = aggregations.first(); a; a = aggregations.next()) {
00240                     QString memberType, memberName;
00241                     computeAssocTypeAndRole(a, c, memberType, memberName);
00242                     idl << getIndent() << memberType << " " << memberName << ";" << m_endl;
00243                 }
00244             }
00245             m_indentLevel--;
00246             idl << getIndent() << "};" << m_endl << m_endl;
00247         } else if (stype == "CORBAUnion") {
00248             idl << getIndent() << "// " << stype << " " << c->getName()
00249             << " is Not Yet Implemented" << m_endl << m_endl;
00250         } else if (stype == "CORBATypedef") {
00251             UMLClassifierList superclasses = c->getSuperClasses();
00252             UMLClassifier* firstParent = superclasses.first();
00253             idl << getIndent() << "typedef " << firstParent->getName() << " "
00254             << c->getName() << ";" << m_endl << m_endl;
00255         } else {
00256             idl << getIndent() << "// " << stype << ": Unknown stereotype" << m_endl << m_endl;
00257         }
00258         // Close the modules inside which we might be nested.
00259         for (pkg = pkgList.first(); pkg != NULL; pkg = pkgList.next()) {
00260             m_indentLevel--;
00261             idl << getIndent() << "};" << m_endl << m_endl;
00262         }
00263         return;
00264     }
00265 
00266     idl << getIndent();
00267     if (c->getAbstract())
00268         idl << "abstract ";
00269     bool isValuetype = (c->getStereotype() == "CORBAValue");
00270     if (isValuetype)
00271         idl << "valuetype ";
00272     else
00273         idl << "interface ";
00274     idl << c->getName();
00275     UMLClassifierList superclasses = c->getSuperClasses();
00276     if (! superclasses.isEmpty()) {
00277         idl << " : ";
00278         UMLClassifier *parent = superclasses.first();
00279         int n_parents = superclasses.count();
00280         while (n_parents--) {
00281             idl << parent->getFullyQualifiedName("::");
00282             if (n_parents)
00283                 idl << ", ";
00284             parent = superclasses.next();
00285         }
00286     }
00287     idl << " {" << m_endl << m_endl;
00288     m_indentLevel++;
00289 
00290     // Generate auxiliary declarations for multiplicity of associations
00291     UMLAssociation *a;
00292     bool didComment = false;
00293     UMLAssociationList assocs = c->getAssociations();
00294     for (a = assocs.first(); a; a = assocs.next()) {
00295         if (! assocTypeIsMappableToAttribute(a->getAssocType()))
00296             continue;
00297         QString multiplicity = a->getMulti(Uml::A);
00298         if (multiplicity.isEmpty() || multiplicity == "1")
00299             continue;
00300         if (!didComment) {
00301             idl << getIndent() << "// Types for association multiplicities" << m_endl << m_endl;
00302             didComment = true;
00303         }
00304         UMLClassifier* other = (UMLClassifier*)a->getObject(Uml::A);
00305         QString bareName = cleanName(other->getName());
00306         idl << getIndent() << "typedef sequence<" << other->getFullyQualifiedName("::")
00307         << "> " << bareName << "Vector;" << m_endl << m_endl;
00308     }
00309 
00310     // Generate public attributes.
00311     if (isClass) {
00312         UMLAttributeList atl = c->getAttributeList();
00313         if (forceSections() || atl.count()) {
00314             idl << getIndent() << "// Attributes:" << m_endl << m_endl;
00315             for (UMLAttribute *at = atl.first(); at; at = atl.next()) {
00316                 QString attName = cleanName(at->getName());
00317                 Uml::Visibility scope = at->getVisibility();
00318                 idl << getIndent();
00319                 if (isValuetype) {
00320                     if (scope == Uml::Visibility::Public)
00321                         idl << "public ";
00322                     else
00323                         idl << "private ";
00324                 } else {
00325                     if (scope != Uml::Visibility::Public) {
00326                         idl << "// visibility should be: "
00327                         << scope.toString()
00328                         << m_endl;
00329                         idl << getIndent();
00330                     }
00331                     idl << "attribute ";
00332                 }
00333                 idl << at->getTypeName() << " " << attName << ";"
00334                 << m_endl << m_endl;
00335             }
00336         }
00337     }
00338 
00339     // Generate public operations.
00340     UMLOperationList opl(c->getOpList());
00341     UMLOperationList oppub;
00342     UMLOperation *op;
00343     for (op = opl.first(); op; op = opl.next()) {
00344           if (op->getVisibility() == Uml::Visibility::Public)
00345             oppub.append(op);
00346     }
00347     if (forceSections() || oppub.count()) {
00348         idl << getIndent() << "// Public methods:" << m_endl << m_endl;
00349         for (op = oppub.first(); op; op = oppub.next())
00350             writeOperation(op, idl);
00351         idl << m_endl;
00352     }
00353 
00354 
00355     if (forceSections() || !assocs.isEmpty()) {
00356         idl << getIndent() << "// Associations:" << m_endl << m_endl;
00357         for (a = assocs.first(); a; a = assocs.next()) {
00358             Uml::Association_Type at = a->getAssocType();
00359             if (! assocTypeIsMappableToAttribute(at))
00360                 continue;
00361             QString typeName, roleName;
00362             computeAssocTypeAndRole(a, c, typeName, roleName);
00363             if (roleName.isEmpty())  // presumably because we are at the "wrong" end
00364                 continue;
00365             idl << getIndent() << "// " << UMLAssociation::typeAsString(at) << m_endl;
00366             idl << getIndent();
00367             if (isValuetype)
00368                 idl << "public ";
00369             else
00370                 idl << "attribute ";
00371             idl << typeName << " " << roleName << ";" << m_endl;
00372         }
00373         idl << m_endl;
00374     }
00375 
00376     m_indentLevel--;
00377     idl << getIndent() << "};" << m_endl << m_endl;
00378 
00379     // Close the modules inside which we might be nested.
00380     for (pkg = pkgList.first(); pkg != NULL; pkg = pkgList.next()) {
00381         m_indentLevel--;
00382         idl << getIndent() << "};" << m_endl << m_endl;
00383     }
00384     file.close();
00385     emit codeGenerated(c, true);
00386 }
00387 
00388 
00389 void IDLWriter::writeOperation(UMLOperation *op, QTextStream &idl, bool is_comment) {
00390     UMLAttributeList atl = op->getParmList();
00391     QString rettype = op->getTypeName();
00392 
00393     if (rettype.isEmpty())
00394         rettype = "void";
00395     idl << getIndent();
00396     if (is_comment)
00397         idl << "// ";
00398     idl << rettype << " " << cleanName(op->getName()) << " (";
00399     if (atl.count()) {
00400         idl << m_endl;
00401         m_indentLevel++;
00402         uint i = 0;
00403         for (UMLAttribute *at = atl.first(); at; at = atl.next()) {
00404             idl << getIndent();
00405             if (is_comment)
00406                 idl << "// ";
00407             Uml::Parameter_Direction pk = at->getParmKind();
00408             if (pk == Uml::pd_Out)
00409                 idl << "out ";
00410             else if (pk == Uml::pd_InOut)
00411                 idl << "inout ";
00412             else
00413                 idl << "in ";
00414             idl << at->getTypeName() << " " << cleanName(at->getName());
00415             if (++i < atl.count())
00416                 idl << "," << m_endl;
00417         }
00418         m_indentLevel--;
00419     }
00420     idl << ");" << m_endl << m_endl;
00421 }
00422 
00423 QStringList IDLWriter::defaultDatatypes() {
00424     QStringList l;
00425     l.append("boolean");
00426     l.append("char");
00427     l.append("octet");
00428     l.append("short");
00429     l.append("unsigned short");
00430     l.append("long");
00431     l.append("unsigned long");
00432     l.append("float");
00433     l.append("double");
00434     l.append("string");
00435     l.append("any");
00436     return l;
00437 }
00438 
00439 const QStringList IDLWriter::reservedKeywords() const {
00440 
00441     static QStringList keywords;
00442 
00443     if (keywords.isEmpty()) {
00444         keywords << "any"
00445         << "attribute"
00446         << "boolean"
00447         << "case"
00448         << "char"
00449         << "const"
00450         << "context"
00451         << "default"
00452         << "double"
00453         << "enum"
00454         << "exception"
00455         << "FALSE"
00456         << "float"
00457         << "in"
00458         << "inout"
00459         << "interface"
00460         << "long"
00461         << "module"
00462         << "octet"
00463         << "oneway"
00464         << "out"
00465         << "raises"
00466         << "readonly"
00467         << "sequence"
00468         << "short"
00469         << "string"
00470         << "struct"
00471         << "switch"
00472         << "TRUE"
00473         << "typedef"
00474         << "union"
00475         << "unsigned"
00476         << "void";
00477     }
00478 
00479     return keywords;
00480 }
00481 
00482 
KDE Logo
This file is part of the documentation for umbrello Version 3.1.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Jun 26 08:07:57 2007 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003