codegenerator.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "codegenerator.h"
00019
00020
00021 #include <cstdlib>
00022
00023
00024 #include <qdatetime.h>
00025 #include <qregexp.h>
00026 #include <qdir.h>
00027 #include <qtextstream.h>
00028
00029
00030 #include <kdebug.h>
00031 #include <klocale.h>
00032 #include <kmessagebox.h>
00033 #include <kdialogbase.h>
00034 #include <kapplication.h>
00035
00036
00037 #include "dialogs/overwritedialogue.h"
00038 #include "dialogs/codeviewerdialog.h"
00039 #include "codegenerators/simplecodegenerator.h"
00040 #include "attribute.h"
00041 #include "association.h"
00042 #include "classifier.h"
00043 #include "classifiercodedocument.h"
00044 #include "codedocument.h"
00045 #include "codegenerationpolicy.h"
00046 #include "operation.h"
00047 #include "uml.h"
00048 #include "umldoc.h"
00049 #include "umlobject.h"
00050 #include "umlattributelist.h"
00051 #include "umloperationlist.h"
00052 #include "model_utils.h"
00053
00054
00055
00056
00057 CodeGenerator::CodeGenerator ()
00058 : QObject (UMLApp::app()->getDocument())
00059 {
00060 initFields();
00061 }
00062
00063
00064
00065 CodeGenerator::CodeGenerator (QDomElement & element )
00066 : QObject (UMLApp::app()->getDocument()) {
00067 initFields();
00068 loadFromXMI(element);
00069 }
00070
00071 CodeGenerator::~CodeGenerator ( ) {
00072
00073 CodeDocument *doc;
00074 for (CodeDocumentListIt it(m_codedocumentVector);
00075 (doc = it.current()) != NULL; ++it)
00076 delete doc;
00077 m_codedocumentVector.clear();
00078 }
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088 QString CodeGenerator::getUniqueID(CodeDocument * codeDoc)
00089 {
00090
00091 QString id = codeDoc->getID();
00092
00093
00094 if (!id.isEmpty() && findCodeDocumentByID(id))
00095 return id;
00096
00097
00098 ClassifierCodeDocument * classDoc = dynamic_cast<ClassifierCodeDocument*>(codeDoc);
00099 if(classDoc) {
00100 UMLClassifier *c = classDoc->getParentClassifier();
00101 id = ID2STR(c->getID());
00102 } else {
00103
00104 QString prefix = "doc";
00105 QString id = prefix + "_0";
00106 int number = lastIDIndex;
00107 for ( ; findCodeDocumentByID(id); number++) {
00108 id = prefix + '_' + QString::number(number);
00109 }
00110 lastIDIndex = number;
00111 }
00112
00113 return id;
00114 }
00115
00116 CodeDocument * CodeGenerator::findCodeDocumentByID( const QString &tag ) {
00117
00118 CodeDocument * doc = (CodeDocument*)NULL;
00119 if((doc = m_codeDocumentDictionary.find(tag)))
00120 return doc;
00121
00122 return doc;
00123 }
00124
00125 bool CodeGenerator::addCodeDocument ( CodeDocument * doc )
00126 {
00127 QString tag = doc->getID();
00128
00129
00130 if(tag.isEmpty())
00131 {
00132 tag = getUniqueID(doc);
00133 doc->setID(tag);
00134 }
00135
00136 if(m_codeDocumentDictionary.find(tag))
00137 return false;
00138 else
00139 m_codeDocumentDictionary.insert(tag, doc);
00140
00141 m_codedocumentVector.append(doc);
00142 return true;
00143 }
00144
00148 bool CodeGenerator::removeCodeDocument ( CodeDocument * remove_object ) {
00149 QString tag = remove_object->getID();
00150 if(!(tag.isEmpty()))
00151 m_codeDocumentDictionary.remove(tag);
00152 else
00153 return false;
00154
00155 m_codedocumentVector.remove(remove_object);
00156 return true;
00157 }
00158
00164 CodeDocumentList * CodeGenerator::getCodeDocumentList ( ) {
00165 return &m_codedocumentVector;
00166 }
00167
00168
00169 CodeViewerDialog * CodeGenerator::getCodeViewerDialog ( QWidget* parent, CodeDocument *doc,
00170 Settings::CodeViewerState state)
00171 {
00172 return new CodeViewerDialog(parent, doc, state);
00173 }
00174
00175
00176
00177
00178 void CodeGenerator::loadFromXMI (QDomElement & qElement ) {
00179
00180
00181 if(dynamic_cast<SimpleCodeGenerator*>(this))
00182 return;
00183
00184
00185 QDomNode node = qElement.firstChild();
00186 QDomElement element = node.toElement();
00187 QString langType = Model_Utils::progLangToString( getLanguage() );
00188
00189 if (qElement.tagName() != "codegenerator"
00190 || qElement.attribute("language", "UNKNOWN") != langType)
00191 return;
00192
00193
00194 QDomNode codeDocNode = qElement.firstChild();
00195 QDomElement codeDocElement = codeDocNode.toElement();
00196 while( !codeDocElement.isNull() ) {
00197
00198 QString docTag = codeDocElement.tagName();
00199 if( docTag == "codedocument" ||
00200 docTag == "classifiercodedocument"
00201 ) {
00202 QString id = codeDocElement.attribute( "id", "-1" );
00203 CodeDocument * codeDoc = findCodeDocumentByID(id);
00204 if(codeDoc)
00205 codeDoc->loadFromXMI(codeDocElement);
00206 else {
00207 kWarning()<<" loadFromXMI: missing code document w/ id:"<<id<<", plowing ahead with pre-generated one."<<endl;
00208 }
00209 } else
00210 kWarning()<<" loadFromXMI : got strange codegenerator child node:"<<docTag<<", ignoring."<<endl;
00211
00212 codeDocNode = codeDocElement.nextSibling();
00213 codeDocElement = codeDocNode.toElement();
00214 }
00215 }
00216
00217 void CodeGenerator::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
00218 QString langType = Model_Utils::progLangToString( getLanguage() );
00219 QDomElement docElement = doc.createElement( "codegenerator" );
00220 docElement.setAttribute("language",langType);
00221
00222 CodeDocumentList * docList = getCodeDocumentList();
00223 for (CodeDocument * codeDoc = docList->first(); codeDoc; codeDoc= docList->next())
00224 codeDoc->saveToXMI(doc, docElement);
00225
00226 root.appendChild( docElement );
00227 }
00228
00244 void CodeGenerator::initFromParentDocument( ) {
00245
00246
00247
00248 UMLClassifierList concepts = UMLApp::app()->getDocument()->getClassesAndInterfaces();
00249 for (UMLClassifier *c = concepts.first(); c; c = concepts.next())
00250 {
00251
00252
00253 CodeDocument * codeDoc = findCodeDocumentByClassifier(c);
00254 if (!codeDoc)
00255 {
00256 codeDoc = newClassifierCodeDocument(c);
00257 addCodeDocument(codeDoc);
00258 }
00259 }
00260
00261 }
00262
00268 void CodeGenerator::syncCodeToDocument ( ) {
00269 for (CodeDocument * doc = m_codedocumentVector.first(); doc; doc=m_codedocumentVector.next())
00270 doc->synchronize();
00271 }
00272
00273
00274
00275 void CodeGenerator::checkAddUMLObject (UMLObject * obj) {
00276 if (!obj)
00277 return;
00278
00279 UMLClassifier * c = dynamic_cast<UMLClassifier*>(obj);
00280 if(c) {
00281 CodeDocument * cDoc = newClassifierCodeDocument(c);
00282 addCodeDocument(cDoc);
00283 }
00284 }
00285
00286 void CodeGenerator::checkRemoveUMLObject (UMLObject * obj)
00287 {
00288
00289 if (!obj)
00290 return;
00291
00292 UMLClassifier * c = dynamic_cast<UMLClassifier*>(obj);
00293 if(c) {
00294 ClassifierCodeDocument * cDoc = (ClassifierCodeDocument*) findCodeDocumentByClassifier(c);
00295 if (cDoc)
00296 removeCodeDocument(cDoc);
00297 }
00298
00299 }
00300
00305 CodeDocument * CodeGenerator::findCodeDocumentByClassifier ( UMLClassifier * classifier ) {
00306 return findCodeDocumentByID(ID2STR(classifier->getID()));
00307 }
00308
00309
00313 void CodeGenerator::writeCodeToFile ( )
00314 {
00315 writeListedCodeDocsToFile(&m_codedocumentVector);
00316 }
00317
00318 void CodeGenerator::writeCodeToFile ( UMLClassifierList & concepts) {
00319 CodeDocumentList docs;
00320 docs.setAutoDelete(false);
00321
00322 for (UMLClassifier *concept= concepts.first(); concept; concept= concepts.next())
00323 {
00324 CodeDocument * doc = findCodeDocumentByClassifier(concept);
00325 if(doc)
00326 docs.append(doc);
00327 }
00328
00329 writeListedCodeDocsToFile(&docs);
00330 }
00331
00332
00333 void CodeGenerator::writeListedCodeDocsToFile ( CodeDocumentList * docs ) {
00334
00335
00336 for (CodeDocument *doc = docs->first(); doc; doc = docs->next())
00337 {
00338
00339
00340 ClassifierCodeDocument * cdoc = dynamic_cast<ClassifierCodeDocument *>(doc);
00341 bool codeGenSuccess = false;
00342
00343
00344 if(doc->getWriteOutCode())
00345 {
00346 QString filename = findFileName(doc);
00347
00348 QFile file;
00349 if ( openFile(file,filename) ) {
00350 QTextStream stream(&file);
00351 stream<<doc->toString()<<endl;
00352 file.close();
00353 codeGenSuccess = true;
00354 } else {
00355 kWarning() << "Cannot open file :"<<filename<<" for writing " << endl;
00356 }
00357 }
00358
00359 if(cdoc)
00360 emit codeGenerated(cdoc->getParentClassifier(), codeGenSuccess);
00361
00362 }
00363
00364 }
00365
00370 CodeDocument * CodeGenerator::newCodeDocument ( ) {
00371 CodeDocument * newCodeDoc = new CodeDocument ();
00372 return newCodeDoc;
00373 }
00374
00380 QString CodeGenerator::getHeadingFile( const QString &file ) {
00381 return UMLApp::app()->getCommonPolicy()->getHeadingFile(file);
00382 }
00383
00389 QString CodeGenerator::overwritableName(const QString& name, const QString &extension ) {
00390
00391 CodeGenerationPolicy *pol = UMLApp::app()->getCommonPolicy();
00392 QDir outputDirectory = pol->getOutputDirectory();
00393 QString filename = name + extension;
00394
00395 if (!outputDirectory.exists(filename)) {
00396 return filename;
00397 }
00398
00399 int suffix;
00400 OverwriteDialogue overwriteDialog( name, outputDirectory.absPath(),
00401 m_applyToAllRemaining, kapp -> mainWidget() );
00402 switch (pol->getOverwritePolicy()) {
00403 case CodeGenerationPolicy::Ok:
00404 filename = name + extension;
00405 break;
00406 case CodeGenerationPolicy::Ask:
00407 switch(overwriteDialog.exec()) {
00408 case KDialogBase::Yes:
00409 if ( overwriteDialog.applyToAllRemaining() ) {
00410 pol->setOverwritePolicy(CodeGenerationPolicy::Ok);
00411 filename = name + extension;
00412 } else {
00413 m_applyToAllRemaining = false;
00414 }
00415 break;
00416 case KDialogBase::No:
00417 suffix = 1;
00418 while (1) {
00419 filename = name + "__" + QString::number(suffix) + extension;
00420 if (!outputDirectory.exists(filename))
00421 break;
00422 suffix++;
00423 }
00424 if ( overwriteDialog.applyToAllRemaining() ) {
00425 pol->setOverwritePolicy(CodeGenerationPolicy::Never);
00426 } else {
00427 m_applyToAllRemaining = false;
00428 }
00429 break;
00430 case KDialogBase::Cancel:
00431 if ( overwriteDialog.applyToAllRemaining() ) {
00432 pol->setOverwritePolicy(CodeGenerationPolicy::Cancel);
00433 } else {
00434 m_applyToAllRemaining = false;
00435 }
00436 return QString();
00437 break;
00438 }
00439
00440 break;
00441 case CodeGenerationPolicy::Never:
00442 suffix = 1;
00443 while (1) {
00444 filename = name + "__" + QString::number(suffix) + extension;
00445 if (!outputDirectory.exists(filename))
00446 break;
00447 suffix++;
00448 }
00449 break;
00450 case CodeGenerationPolicy::Cancel:
00451 return QString();
00452 break;
00453 }
00454
00455 return filename;
00456 }
00457
00458
00464 bool CodeGenerator::openFile (QFile & file, const QString &fileName ) {
00465
00466 if(fileName.isEmpty()) {
00467 kWarning() << "cannot find a file name" << endl;
00468 return false;
00469 } else {
00470 QDir outputDirectory = UMLApp::app()->getCommonPolicy()->getOutputDirectory();
00471 file.setName(outputDirectory.absFilePath(fileName));
00472 if(!file.open(IO_WriteOnly)) {
00473 KMessageBox::sorry(0,i18n("Cannot open file %1 for writing. Please make sure the folder exists and you have permissions to write to it.").arg(file.name()),i18n("Cannot Open File"));
00474 return false;
00475 }
00476 return true;
00477 }
00478
00479 }
00480
00481
00486 QString CodeGenerator::cleanName ( const QString &name ) {
00487 QString retval = name;
00488 retval.replace(QRegExp("\\W"), "_");
00489 return retval;
00490 }
00491
00492 QString CodeGenerator::findFileName ( CodeDocument * codeDocument ) {
00493
00494
00495 QString name;
00496
00497
00498 QString path = codeDocument->getPath();
00499
00500
00501 if (!path.isEmpty()) {
00502 path.replace(QRegExp("::"), "/");
00503 name = path + '/' + codeDocument->getFileName();
00504 path = '/' + path;
00505 } else {
00506 name = codeDocument->getFileName();
00507 }
00508
00509
00510 name.replace(QRegExp("::"), "/");
00511
00512
00513 if (!path.isEmpty()) {
00514 QDir outputDirectory = UMLApp::app()->getCommonPolicy()->getOutputDirectory();
00515 QDir pathDir(outputDirectory.absPath() + path);
00516
00517
00518 if (!pathDir.exists())
00519 {
00520
00521 QStringList dirs = QStringList::split("/",pathDir.absPath());
00522 QString currentDir = "";
00523
00524 QStringList::iterator end(dirs.end());
00525 for (QStringList::iterator dir(dirs.begin()); dir != end; ++dir)
00526 {
00527 currentDir += '/' + *dir;
00528 if (! (pathDir.exists(currentDir)
00529 || pathDir.mkdir(currentDir) ) )
00530 {
00531 KMessageBox::error(0, i18n("Cannot create the folder:\n") +
00532 pathDir.absPath() + i18n("\nPlease check the access rights"),
00533 i18n("Cannot Create Folder"));
00534 return NULL;
00535
00536 }
00537 }
00538 }
00539 }
00540
00541 name.simplifyWhiteSpace();
00542 name.replace(QRegExp(" "),"_");
00543
00544 return overwritableName( name, codeDocument->getFileExtension() );
00545 }
00546
00547 void CodeGenerator::findObjectsRelated(UMLClassifier *c, UMLPackageList &cList) {
00548 UMLPackage *temp;
00549 UMLAssociationList associations = c->getAssociations();
00550
00551 for (UMLAssociation *a = associations.first(); a; a = associations.next()) {
00552 temp = 0;
00553 switch (a->getAssocType()) {
00554 case Uml::at_Generalization:
00555 case Uml::at_Realization:
00556
00557 {
00558 UMLObject *objB = a->getObject(Uml::B);
00559 if (objB != c)
00560 temp = (UMLPackage*)objB;
00561 }
00562 break;
00563 case Uml::at_Dependency:
00564 case Uml::at_UniAssociation:
00565 {
00566 UMLObject *objA = a->getObject(Uml::A);
00567 UMLObject *objB = a->getObject(Uml::B);
00568 if (objA == c)
00569 temp = static_cast<UMLPackage*>(objB);
00570 }
00571 break;
00572 case Uml::at_Aggregation:
00573 case Uml::at_Composition:
00574 case Uml::at_Association:
00575 {
00576 UMLObject *objA = a->getObject(Uml::A);
00577 UMLObject *objB = a->getObject(Uml::B);
00578 if (objA == c && objB->getBaseType() != Uml::ot_Datatype)
00579 temp = static_cast<UMLPackage*>(objB);
00580 }
00581 break;
00582 default:
00583 break;
00584 }
00585
00586
00587 if(temp && !cList.containsRef(temp))
00588 cList.append(temp);
00589 }
00590
00591
00592 UMLOperationList opl(c->getOpList());
00593 for(UMLOperation *op = opl.first(); op ; op = opl.next()) {
00594 temp =0;
00595
00596 temp =(UMLClassifier*) op->getType();
00597 if (temp && temp->getBaseType() != Uml::ot_Datatype && !cList.containsRef(temp))
00598 cList.append(temp);
00599
00600 UMLAttributeList atl = op->getParmList();
00601 for (UMLAttribute *at = atl.first(); at; at = atl.next()) {
00602 temp = (UMLClassifier*)at->getType();
00603 if (temp && temp->getBaseType() != Uml::ot_Datatype && !cList.containsRef(temp))
00604 cList.append(temp);
00605 }
00606
00607 }
00608
00609
00610 if (!c->isInterface()) {
00611 UMLAttributeList atl = c->getAttributeList();
00612 for (UMLAttribute *at = atl.first(); at; at = atl.next()) {
00613 temp=0;
00614 temp = (UMLClassifier*) at->getType();
00615 if (temp && temp->getBaseType() != Uml::ot_Datatype && !cList.containsRef(temp))
00616 cList.append(temp);
00617 }
00618 }
00619
00620
00621 }
00622
00630 QString CodeGenerator::formatDoc(const QString &text, const QString &linePrefix, int lineWidth) {
00631 QString output;
00632
00633 const QString endLine = UMLApp::app()->getCommonPolicy()->getNewLineEndingChars();
00634 QStringList lines = QStringList::split(endLine, text);
00635 for (QStringList::ConstIterator lit = lines.begin(); lit != lines.end(); ++lit) {
00636 QString input = *lit;
00637 input.remove( QRegExp("\\s+$") );
00638 if (input.length() < (uint)lineWidth) {
00639 output += linePrefix + input + endLine;
00640 continue;
00641 }
00642 int index;
00643 while ((index = input.findRev(" ", lineWidth)) >= 0) {
00644 output += linePrefix + input.left(index) + endLine;
00645 input.remove(0, index + 1);
00646
00647 }
00648 if (!input.isEmpty())
00649 output += linePrefix + input + endLine;
00650 }
00651 return output;
00652 }
00653
00654 void CodeGenerator::initFields() {
00655
00656 m_document = UMLApp::app()->getDocument();
00657 m_codeDocumentDictionary.setAutoDelete(false);
00658 m_codedocumentVector.setAutoDelete(false);
00659 m_applyToAllRemaining = true;
00660 lastIDIndex = 0;
00661
00662
00663
00664
00665
00666
00667
00668 }
00669
00670 void CodeGenerator::connect_newcodegen_slots() {
00671 UMLDoc *doc = UMLApp::app()->getDocument();
00672 connect(doc, SIGNAL(sigObjectCreated(UMLObject*)),
00673 this, SLOT(checkAddUMLObject(UMLObject*)));
00674 connect(doc, SIGNAL(sigObjectRemoved(UMLObject*)),
00675 this, SLOT(checkRemoveUMLObject(UMLObject*)));
00676 CodeGenerationPolicy *commonPolicy = UMLApp::app()->getCommonPolicy();
00677 connect(commonPolicy, SIGNAL(modifiedCodeContent()),
00678 this, SLOT(syncCodeToDocument()));
00679 }
00680
00681
00682
00683
00684 void CodeGenerator::setForceDoc(bool f) {
00685 UMLApp::app()->getCommonPolicy()->setCodeVerboseDocumentComments(f);
00686 }
00687
00688 bool CodeGenerator::forceDoc() const {
00689 return UMLApp::app()->getCommonPolicy()->getCodeVerboseDocumentComments();
00690 }
00691
00692 void CodeGenerator::setForceSections(bool f) {
00693 UMLApp::app()->getCommonPolicy()->setCodeVerboseSectionComments(f);
00694 }
00695
00696 bool CodeGenerator::forceSections() const {
00697 return UMLApp::app()->getCommonPolicy()->getCodeVerboseSectionComments();
00698 }
00699
00700 QStringList CodeGenerator::defaultDatatypes() {
00701 return QStringList();
00702
00703 }
00704
00705 bool CodeGenerator::isReservedKeyword(const QString & keyword) {
00706
00707 const QStringList keywords = reservedKeywords();
00708
00709 return keywords.contains(keyword);
00710 }
00711
00712 const QStringList CodeGenerator::reservedKeywords() const {
00713 static QStringList emptyList;
00714
00715 return emptyList;
00716 }
00717
00718 void CodeGenerator::createDefaultStereotypes() {
00719
00720
00721 }
00722
00723 #include "codegenerator.moc"
This file is part of the documentation for umbrello Version 3.1.0.