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.
309 lines
9.6 KiB
309 lines
9.6 KiB
/***************************************************************************
|
|
begin : Sat Feb 08 2003
|
|
copyright : (C) 2003 by Alexander Blum
|
|
email : blum@kewbee.de
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License js published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "jswriter.h"
|
|
#include "../association.h"
|
|
#include "../classifier.h"
|
|
#include "../operation.h"
|
|
#include "../umldoc.h"
|
|
#include "../attribute.h"
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <tqregexp.h>
|
|
#include <tqtextstream.h>
|
|
|
|
JSWriter::JSWriter() {
|
|
}
|
|
|
|
JSWriter::~JSWriter() {}
|
|
|
|
|
|
void JSWriter::writeClass(UMLClassifier *c)
|
|
{
|
|
if(!c)
|
|
{
|
|
kDebug()<<"Cannot write class of NULL concept!" << endl;
|
|
return;
|
|
}
|
|
|
|
TQString classname = cleanName(c->getName());
|
|
TQString fileName = c->getName().lower();
|
|
|
|
//find an appropriate name for our file
|
|
fileName = findFileName(c,".js");
|
|
if (fileName.isEmpty())
|
|
{
|
|
emit codeGenerated(c, false);
|
|
return;
|
|
}
|
|
|
|
TQFile filejs;
|
|
if(!openFile(filejs, fileName))
|
|
{
|
|
emit codeGenerated(c, false);
|
|
return;
|
|
}
|
|
TQTextStream js(&filejs);
|
|
|
|
//////////////////////////////
|
|
//Start generating the code!!
|
|
/////////////////////////////
|
|
|
|
|
|
//try to find a heading file (license, coments, etc)
|
|
TQString str;
|
|
str = getHeadingFile(".js");
|
|
if(!str.isEmpty())
|
|
{
|
|
str.replace(TQRegExp("%filename%"),fileName);
|
|
str.replace(TQRegExp("%filepath%"),filejs.name());
|
|
js << str << m_endl;
|
|
}
|
|
|
|
|
|
//write includes
|
|
UMLPackageList includes;
|
|
findObjectsRelated(c,includes);
|
|
for (UMLPackage *conc = includes.first(); conc; conc = includes.next())
|
|
{
|
|
TQString headerName = findFileName(conc, ".js");
|
|
if ( !headerName.isEmpty() )
|
|
{
|
|
js << "#include \"" << headerName << "\"" << m_endl;
|
|
}
|
|
}
|
|
js << m_endl;
|
|
|
|
//Write class Documentation if there is somthing or if force option
|
|
if(forceDoc() || !c->getDoc().isEmpty())
|
|
{
|
|
js << m_endl << "/**" << m_endl;
|
|
js << " * class " << classname << m_endl;
|
|
js << formatDoc(c->getDoc()," * ");
|
|
js << " */" << m_endl << m_endl;
|
|
}
|
|
|
|
|
|
//check if class is abstract and / or has abstract methods
|
|
if(c->getAbstract() && !hasAbstractOps(c))
|
|
js << "/******************************* Abstract Class ****************************" << m_endl << " "
|
|
<< 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;
|
|
|
|
js << classname << " = function ()" << m_endl;
|
|
js << "{" << m_endl;
|
|
js << m_indentation << "this._init ();" << m_endl;
|
|
js << "}" << m_endl;
|
|
js << m_endl;
|
|
|
|
UMLClassifierList superclasses = c->getSuperClasses();
|
|
for (UMLClassifier *obj = superclasses.first();
|
|
obj; obj = superclasses.next()) {
|
|
js << classname << ".prototype = new " << cleanName(obj->getName()) << " ();" << m_endl;
|
|
}
|
|
|
|
js << m_endl;
|
|
|
|
if (! c->isInterface()) {
|
|
UMLAttributeList atl = c->getAttributeList();
|
|
|
|
js << "/**" << m_endl;
|
|
TQString temp = "_init sets all " + classname + " attributes to their default value."
|
|
" Make sure to call this method within your class constructor";
|
|
js << formatDoc(temp, " * ");
|
|
js << " */" << m_endl;
|
|
js << classname << ".prototype._init = function ()" << m_endl;
|
|
js << "{" << m_endl;
|
|
for(UMLAttribute *at = atl.first(); at ; at = atl.next())
|
|
{
|
|
if (forceDoc() || !at->getDoc().isEmpty())
|
|
{
|
|
js << m_indentation << "/**" << m_endl
|
|
<< formatDoc(at->getDoc(), m_indentation + " * ")
|
|
<< m_indentation << " */" << m_endl;
|
|
}
|
|
if(!at->getInitialValue().isEmpty())
|
|
{
|
|
js << m_indentation << "this.m_" << cleanName(at->getName()) << " = " << at->getInitialValue() << ";" << m_endl;
|
|
}
|
|
else
|
|
{
|
|
js << m_indentation << "this.m_" << cleanName(at->getName()) << " = \"\";" << m_endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
//associations
|
|
UMLAssociationList aggregations = c->getAggregations();
|
|
if (forceSections() || !aggregations.isEmpty ())
|
|
{
|
|
js << m_endl << m_indentation << "/**Aggregations: */" << m_endl;
|
|
writeAssociation(classname, aggregations , js );
|
|
|
|
}
|
|
UMLAssociationList compositions = c->getCompositions();
|
|
if( forceSections() || !compositions.isEmpty())
|
|
{
|
|
js << m_endl << m_indentation << "/**Compositions: */" << m_endl;
|
|
writeAssociation(classname, compositions , js );
|
|
|
|
}
|
|
js << m_endl;
|
|
js << "}" << m_endl;
|
|
js << m_endl;
|
|
|
|
//operations
|
|
UMLOperationList ops(c->getOpList());
|
|
writeOperations(classname, &ops, js);
|
|
|
|
js << m_endl;
|
|
|
|
//finish file
|
|
|
|
//close files and notfiy we are done
|
|
filejs.close();
|
|
emit codeGenerated(c, true);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// Helper Methods
|
|
|
|
void JSWriter::writeAssociation(TQString& classname, UMLAssociationList& assocList , TQTextStream &js)
|
|
{
|
|
for (UMLAssociation *a = assocList.first(); a; a = assocList.next()) {
|
|
// association side
|
|
Uml::Role_Type role = (a->getObject(Uml::A)->getName() == classname ? Uml::B : Uml::A);
|
|
|
|
TQString roleName(cleanName(a->getRoleName(role)));
|
|
|
|
if (!roleName.isEmpty()) {
|
|
|
|
// association doc
|
|
if (forceDoc() || !a->getDoc().isEmpty())
|
|
{
|
|
js << m_indentation << "/**" << m_endl
|
|
<< formatDoc(a->getDoc(), m_indentation + " * ")
|
|
<< m_indentation << " */" << m_endl;
|
|
}
|
|
|
|
// role doc
|
|
if (forceDoc() || !a->getRoleDoc(role).isEmpty())
|
|
{
|
|
js << m_indentation << "/**" << m_endl
|
|
<< formatDoc(a->getRoleDoc(role), m_indentation + " * ")
|
|
<< m_indentation << " */" << m_endl;
|
|
}
|
|
|
|
bool okCvt;
|
|
int nMulti = a->getMulti(role).toInt(&okCvt,10);
|
|
bool isNotMulti = a->getMulti(role).isEmpty() || (okCvt && nMulti == 1);
|
|
|
|
TQString typeName(cleanName(a->getObject(role)->getName()));
|
|
|
|
if (isNotMulti)
|
|
js << m_indentation << "this.m_" << roleName << " = new " << typeName << "();" << m_endl;
|
|
else
|
|
js << m_indentation << "this.m_" << roleName << " = new Array();" << m_endl;
|
|
|
|
// role visibility
|
|
}
|
|
}
|
|
}
|
|
|
|
void JSWriter::writeOperations(TQString classname, UMLOperationList *opList, TQTextStream &js)
|
|
{
|
|
UMLOperation *op;
|
|
UMLAttribute *at;
|
|
|
|
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();
|
|
|
|
if( writeDoc ) //write method documentation
|
|
{
|
|
js << "/**" << m_endl << formatDoc(op->getDoc()," * ");
|
|
|
|
for (at = atl.first(); at; at = atl.next()) //write parameter documentation
|
|
{
|
|
if(forceDoc() || !at->getDoc().isEmpty())
|
|
{
|
|
js << " * @param " + cleanName(at->getName())<<m_endl;
|
|
js << formatDoc(at->getDoc()," * ");
|
|
}
|
|
}//end for : write parameter documentation
|
|
js << " */" << m_endl;
|
|
}//end if : write method documentation
|
|
|
|
js << classname << ".prototype." << cleanName(op->getName()) << " = function " << "(";
|
|
|
|
int i = atl.count();
|
|
int j=0;
|
|
for (at = atl.first(); at ;at = atl.next(),j++)
|
|
{
|
|
js << cleanName(at->getName())
|
|
<< (!(at->getInitialValue().isEmpty()) ? (TQString(" = ")+at->getInitialValue()) : TQString(""))
|
|
<< ((j < i-1)?", ":"");
|
|
}
|
|
js << ")" << m_endl << "{" << m_endl <<
|
|
m_indentation << m_endl << "}" << m_endl;
|
|
js << m_endl << m_endl;
|
|
}//end for
|
|
}
|
|
|
|
/**
|
|
* returns "JavaScript"
|
|
*/
|
|
Uml::Programming_Language JSWriter::getLanguage() {
|
|
return Uml::pl_JavaScript;
|
|
}
|
|
|
|
const TQStringList JSWriter::reservedKeywords() const {
|
|
|
|
static TQStringList keywords;
|
|
|
|
if (keywords.isEmpty()) {
|
|
keywords << "break"
|
|
<< "case"
|
|
<< "const"
|
|
<< "continue"
|
|
<< "default"
|
|
<< "else"
|
|
<< "false"
|
|
<< "for"
|
|
<< "function"
|
|
<< "if"
|
|
<< "in"
|
|
<< "new"
|
|
<< "return"
|
|
<< "switch"
|
|
<< "this"
|
|
<< "true"
|
|
<< "var"
|
|
<< "while"
|
|
<< "with";
|
|
}
|
|
|
|
return keywords;
|
|
}
|
|
|
|
#include "jswriter.moc"
|