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.
tdesdk/umbrello/umbrello/codegenerators/pythonwriter.cpp

439 lines
12 KiB

/***************************************************************************
pythonwriter.h - description
-------------------
begin : Sat Dec 21 2002
copyright : Vincent Decorges
email : vincent.decorges@eivd.ch
(C) 2003-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. *
* *
***************************************************************************/
#include "pythonwriter.h"
#include <kdebug.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <tqfile.h>
#include <tqtextstream.h>
#include <tqregexp.h>
#include "../umldoc.h"
#include "../umlattributelist.h"
#include "../association.h"
#include "../attribute.h"
#include "../classifier.h"
#include "../attribute.h"
#include "../operation.h"
#include "../umlnamespace.h"
PythonWriter::PythonWriter() : m_bNeedPass(true) {
}
PythonWriter::~PythonWriter() {}
void PythonWriter::writeClass(UMLClassifier *c) {
if(!c) {
kDebug()<<"Cannot write class of NULL concept!" << endl;
return;
}
TQString classname = cleanName(c->getName());
UMLClassifierList superclasses = c->getSuperClasses();
UMLAssociationList aggregations = c->getAggregations();
UMLAssociationList compositions = c->getCompositions();
m_bNeedPass = true;
//find an appropriate name for our file
TQString fileName = findFileName(c, ".py");
if (fileName.isEmpty()) {
emit codeGenerated(c, false);
return;
}
TQChar first = fileName.at(0);
//Replace the first letter of the filename because
//python class begin with an upper caracter (convention)
first = first.upper();
fileName = fileName.replace(0, 1, first);
TQFile fileh;
if( !openFile(fileh, fileName) ) {
emit codeGenerated(c, false);
return;
}
TQTextStream h(&fileh);
//////////////////////////////
//Start generating the code!!
/////////////////////////////
//try to find a heading file (license, coments, etc)
TQString str;
str = getHeadingFile(".py");
if(!str.isEmpty()) {
str.replace(TQRegExp("%filename%"), fileName);
str.replace(TQRegExp("%filepath%"), fileh.name());
h<<str<<m_endl;
}
// generate import statement for superclasses and take packages into account
str = cleanName(c->getName());
TQString pkg = cleanName(c->getPackage());
if (!pkg.isEmpty())
str.prepend(pkg + '.');
TQStringList includesList = TQStringList(str); //save imported classes
int i = superclasses.count();
for (UMLClassifier *classifier = superclasses.first();
classifier && i; classifier = superclasses.next(), i--) {
str = cleanName(classifier->getName());
pkg = cleanName(classifier->getPackage());
if (!pkg.isEmpty())
str.prepend(pkg + '.');
includesList.append(str);
h << "from " + str + " import *" << m_endl;
}
//write includes and take namespaces into account
UMLPackageList includes;
findObjectsRelated(c,includes);
UMLPackage* conc;
for(conc = includes.first(); conc ;conc = includes.next()) {
TQString headerName = findFileName(conc, ".py");
if ( !headerName.isEmpty() ) {
headerName.remove(TQRegExp(".py$"));
first = headerName.at(0);
first = first.upper();
headerName = headerName.replace(0, 1, first);
str = headerName.replace(TQChar('/'),TQChar('.'));
if (includesList.findIndex(str) < 0) // not yet imported
h << "from " << str << " import *" << m_endl;
}
}
h<<m_endl;
h << "class " << classname << (superclasses.count() > 0 ? " (" : "(object)");
i = superclasses.count();
for (UMLClassifier *obj = superclasses.first();
obj && i; obj = superclasses.next(), i--) {
h<<cleanName(obj->getName())<<(i>1?", ":"");
}
h<<(superclasses.count() > 0 ? ")":"")<<":"<<m_endl<<m_endl;
if (forceDoc() || !c->getDoc().isEmpty()) {
h << m_indentation << "\"\"\"" << m_endl;
h << formatDoc(c->getDoc(), m_indentation + ' ') << m_endl;
h << m_indentation << ":version:" << m_endl;
h << m_indentation << ":author:" << m_endl;
h << m_indentation << "\"\"\"" << m_endl << m_endl;
m_bNeedPass = false;
}
// attributes
writeAttributes(c->getAttributeList(), h);
//operations
writeOperations(c,h);
if (m_bNeedPass)
h << m_indentation << "pass" << m_endl;
//finish files
h<<m_endl<<m_endl;
//close files and notfiy we are done
fileh.close();
emit codeGenerated(c, true);
}
////////////////////////////////////////////////////////////////////////////////////
// Helper Methods
void PythonWriter::writeAttributes(UMLAttributeList atList, TQTextStream &py) {
if (!forceDoc() || atList.count() == 0)
return;
py << m_indentation << "\"\"\" ATTRIBUTES" << m_endl << m_endl;
for (UMLAttribute *at = atList.first(); at; at = atList.next()) {
py << formatDoc(at->getDoc(), m_indentation + ' ') << m_endl;
Uml::Visibility vis = at->getVisibility();
py << m_indentation << cleanName(at->getName()) << " ("
<< vis.toString() << ")" << m_endl << m_endl ;
} // end for
py << m_indentation << "\"\"\"" << m_endl << m_endl;
}
void PythonWriter::writeOperations(UMLClassifier *c, TQTextStream &h) {
//Lists to store operations sorted by scope
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
UMLOperationList opl(c->getOpList());
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:
break;
}
}
TQString classname(cleanName(c->getName()));
//write operations to file
if(forceSections() || !oppub.isEmpty()) {
writeOperations(classname,oppub,h,PUBLIC);
}
if(forceSections() || !opprot.isEmpty()) {
writeOperations(classname,opprot,h,PROTECTED);
}
if(forceSections() || !oppriv.isEmpty()) {
writeOperations(classname,oppriv,h,PRIVATE);
}
}
void PythonWriter::writeOperations(const TQString& /*classname*/, UMLOperationList &opList,
TQTextStream &h, Access access) {
UMLOperation *op;
UMLAttribute *at;
TQString sAccess;
switch (access) {
case PUBLIC:
sAccess = TQString("");
break;
case PRIVATE:
sAccess = TQString("__");
break;
case PROTECTED:
sAccess = TQString("_");
break;
}
for(op=opList.first(); op ; op=opList.next()) {
UMLAttributeList atl = op->getParmList();
//write method doc if we have doc || if at least one of the params has doc
bool writeDoc = forceDoc() || !op->getDoc().isEmpty();
for (at = atl.first(); at; at = atl.next())
writeDoc |= !at->getDoc().isEmpty();
h<< m_indentation << "def "<< sAccess + cleanName(op->getName()) << "(self";
int j=0;
for (at = atl.first(); at; at = atl.next(), j++) {
h << ", " << cleanName(at->getName())
<< (!(at->getInitialValue().isEmpty()) ?
(TQString(" = ")+at->getInitialValue()) :
TQString(""));
}
h<<"):"<<m_endl;
if( writeDoc ) //write method documentation
{
h << m_indentation << m_indentation << "\"\"\"" << m_endl;
h << formatDoc(op->getDoc(), m_indentation + m_indentation + ' ') << m_endl;
for (at = atl.first(); at; at = atl.next()) //write parameter documentation
{
if(forceDoc() || !at->getDoc().isEmpty()) {
h<<m_indentation<<m_indentation<<"@param "<<at->getTypeName()<<
" " << cleanName(at->getName());
h<<" : "<<at->getDoc()<<m_endl;
}
}//end for : write parameter documentation
h<<m_indentation<<m_indentation<<"@return " + op->getTypeName()<<" :"<<m_endl;
h<<m_indentation<<m_indentation<<"@author"<<m_endl;
h<<m_indentation<<m_indentation<<"\"\"\""<<m_endl;
}
h<<m_indentation<<m_indentation<<"pass"<<m_endl<<m_endl;
m_bNeedPass = false;
}//end for
}
/**
* returns "Python"
*/
Uml::Programming_Language PythonWriter::getLanguage() {
return Uml::pl_Python;
}
const TQStringList PythonWriter::reservedKeywords() const {
static TQStringList keywords;
if (keywords.isEmpty()) {
keywords << "abs"
<< "and"
<< "apply"
<< "ArithmeticError"
<< "assert"
<< "AssertionError"
<< "AttributeError"
<< "break"
<< "buffer"
<< "callable"
<< "chr"
<< "class"
<< "classmethod"
<< "cmp"
<< "coerce"
<< "compile"
<< "complex"
<< "continue"
<< "def"
<< "del"
<< "delattr"
<< "DeprecationWarning"
<< "dict"
<< "dir"
<< "divmod"
<< "elif"
<< "Ellipsis"
<< "else"
<< "EnvironmentError"
<< "EOFError"
<< "eval"
<< "except"
<< "Exception"
<< "exec"
<< "execfile"
<< "file"
<< "filter"
<< "finally"
<< "float"
<< "FloatingPointError"
<< "for"
<< "from"
<< "getattr"
<< "global"
<< "globals"
<< "hasattr"
<< "hash"
<< "hex"
<< "id"
<< "if"
<< "import"
<< "__import__"
<< "ImportError"
<< "in"
<< "IndentationError"
<< "IndexError"
<< "input"
<< "int"
<< "intern"
<< "IOError"
<< "is"
<< "isinstance"
<< "issubclass"
<< "iter"
<< "KeyboardInterrupt"
<< "KeyError"
<< "lambda"
<< "len"
<< "list"
<< "locals"
<< "long"
<< "LookupError"
<< "map"
<< "max"
<< "MemoryError"
<< "min"
<< "NameError"
<< "None"
<< "not"
<< "NotImplemented"
<< "NotImplementedError"
<< "object"
<< "oct"
<< "open"
<< "or"
<< "ord"
<< "OSError"
<< "OverflowError"
<< "OverflowWarning"
<< "pass"
<< "pow"
<< "print"
<< "property"
<< "raise"
<< "range"
<< "raw_input"
<< "reduce"
<< "ReferenceError"
<< "reload"
<< "repr"
<< "return"
<< "round"
<< "RuntimeError"
<< "RuntimeWarning"
<< "setattr"
<< "slice"
<< "StandardError"
<< "staticmethod"
<< "StopIteration"
<< "str"
<< "super"
<< "SyntaxError"
<< "SyntaxWarning"
<< "SystemError"
<< "SystemExit"
<< "TabError"
<< "try"
<< "tuple"
<< "type"
<< "TypeError"
<< "UnboundLocalError"
<< "unichr"
<< "unicode"
<< "UnicodeError"
<< "UserWarning"
<< "ValueError"
<< "vars"
<< "Warning"
<< "while"
<< "WindowsError"
<< "xrange"
<< "yield"
<< "ZeroDivisionError"
<< "zip";
}
return keywords;
}
#include "pythonwriter.moc"