/***************************************************************************
* *
* 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 ) 2004 - 2007 *
* Umbrello UML Modeller Authors < uml - devel @ uml . sf . net > *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* This code generated by:
* Author : thomas
* Date : Thu Jun 19 2003
*/
// own header
# include "codegenerator.h"
// system includes
# include <cstdlib> //to get the user name
// qt includes
# include <tqdatetime.h>
# include <tqregexp.h>
# include <tqdir.h>
# include <tqtextstream.h>
// kde includes
# include <kdebug.h>
# include <klocale.h>
# include <kmessagebox.h>
# include <kdialogbase.h>
# include <kapplication.h>
// app includes
# include "dialogs/overwritedialogue.h"
# include "dialogs/codeviewerdialog.h"
# include "codegenerators/simplecodegenerator.h"
# include "attribute.h"
# include "association.h"
# include "classifier.h"
# include "classifiercodedocument.h"
# include "codedocument.h"
# include "codegenerationpolicy.h"
# include "operation.h"
# include "uml.h"
# include "umldoc.h"
# include "umlobject.h"
# include "umlattributelist.h"
# include "umloperationlist.h"
# include "model_utils.h"
// Constructors/Destructors
//
CodeGenerator : : CodeGenerator ( )
: TQObject ( UMLApp : : app ( ) - > getDocument ( ) )
{
initFields ( ) ;
}
// FIX
// hmm. this should be pure virtual so that implemented in sub-class
CodeGenerator : : CodeGenerator ( TQDomElement & element )
: TQObject ( UMLApp : : app ( ) - > getDocument ( ) ) {
initFields ( ) ;
loadFromXMI ( element ) ; // hmm. cant call this here.. its 'pure' virtual
}
CodeGenerator : : ~ CodeGenerator ( ) {
// destroy all owned codedocuments
CodeDocument * doc ;
for ( CodeDocumentListIt it ( m_codedocumentVector ) ;
( doc = it . current ( ) ) ! = NULL ; + + it )
delete doc ;
m_codedocumentVector . clear ( ) ;
}
//
// Methods
//
// Accessor methods
//
TQString CodeGenerator : : getUniqueID ( CodeDocument * codeDoc )
{
TQString id = codeDoc - > getID ( ) ;
// does this document already exist? then just return its present id
if ( ! id . isEmpty ( ) & & findCodeDocumentByID ( id ) )
return id ;
// approach now differs by whether or not its a classifier code document
ClassifierCodeDocument * classDoc = dynamic_cast < ClassifierCodeDocument * > ( codeDoc ) ;
if ( classDoc ) {
UMLClassifier * c = classDoc - > getParentClassifier ( ) ;
id = ID2STR ( c - > getID ( ) ) ; // this is supposed to be unique already..
} else {
TQString prefix = " doc " ;
TQString id = prefix + " _0 " ;
int number = lastIDIndex ;
for ( ; findCodeDocumentByID ( id ) ; number + + ) {
id = prefix + ' _ ' + TQString : : number ( number ) ;
}
lastIDIndex = number ;
}
return id ;
}
CodeDocument * CodeGenerator : : findCodeDocumentByID ( const TQString & tag ) {
//if we already know to which file this class was written/should be written, just return it.
CodeDocument * doc = ( CodeDocument * ) NULL ;
if ( ( doc = m_codeDocumentDictionary . find ( tag ) ) )
return doc ;
return doc ;
}
bool CodeGenerator : : addCodeDocument ( CodeDocument * doc )
{
TQString tag = doc - > getID ( ) ;
// assign a tag if one doesn't already exist
if ( tag . isEmpty ( ) )
{
tag = getUniqueID ( doc ) ;
doc - > setID ( tag ) ;
}
if ( m_codeDocumentDictionary . find ( tag ) )
return false ; // return false, we already have some object with this tag in the list
else
m_codeDocumentDictionary . insert ( tag , doc ) ;
m_codedocumentVector . append ( doc ) ;
return true ;
}
/**
* Remove a CodeDocument object from m_codedocumentVector List
*/
bool CodeGenerator : : removeCodeDocument ( CodeDocument * remove_object ) {
TQString tag = remove_object - > getID ( ) ;
if ( ! ( tag . isEmpty ( ) ) )
m_codeDocumentDictionary . remove ( tag ) ;
else
return false ;
m_codedocumentVector . remove ( remove_object ) ;
return true ;
}
/**
* Get the list of CodeDocument objects held by m_codedocumentVector
* @ return TQPtrList < CodeDocument * > list of CodeDocument objects held by
* m_codedocumentVector
*/
CodeDocumentList * CodeGenerator : : getCodeDocumentList ( ) {
return & m_codedocumentVector ;
}
// the vanilla version
CodeViewerDialog * CodeGenerator : : getCodeViewerDialog ( TQWidget * parent , CodeDocument * doc ,
Settings : : CodeViewerState state )
{
return new CodeViewerDialog ( parent , doc , state ) ;
}
// Other methods
//
void CodeGenerator : : loadFromXMI ( TQDomElement & qElement ) {
// don't do anything for simple (compatability) code generators
if ( dynamic_cast < SimpleCodeGenerator * > ( this ) )
return ;
//now look for our particular child element
TQDomNode node = qElement . firstChild ( ) ;
TQDomElement element = node . toElement ( ) ;
TQString langType = Model_Utils : : progLangToString ( getLanguage ( ) ) ;
if ( qElement . tagName ( ) ! = " codegenerator "
| | qElement . attribute ( " language " , " UNKNOWN " ) ! = langType )
return ;
// got our code generator element, now load
// codedocuments
TQDomNode codeDocNode = qElement . firstChild ( ) ;
TQDomElement codeDocElement = codeDocNode . toElement ( ) ;
while ( ! codeDocElement . isNull ( ) ) {
TQString docTag = codeDocElement . tagName ( ) ;
if ( docTag = = " codedocument " | |
docTag = = " classifiercodedocument "
) {
TQString id = codeDocElement . attribute ( " id " , " -1 " ) ;
CodeDocument * codeDoc = findCodeDocumentByID ( id ) ;
if ( codeDoc )
codeDoc - > loadFromXMI ( codeDocElement ) ;
else {
kWarning ( ) < < " loadFromXMI: missing code document w/ id: " < < id < < " , plowing ahead with pre-generated one. " < < endl ;
}
} else
kWarning ( ) < < " loadFromXMI : got strange codegenerator child node: " < < docTag < < " , ignoring. " < < endl ;
codeDocNode = codeDocElement . nextSibling ( ) ;
codeDocElement = codeDocNode . toElement ( ) ;
}
}
void CodeGenerator : : saveToXMI ( TQDomDocument & doc , TQDomElement & root ) {
TQString langType = Model_Utils : : progLangToString ( getLanguage ( ) ) ;
TQDomElement docElement = doc . createElement ( " codegenerator " ) ;
docElement . setAttribute ( " language " , langType ) ;
CodeDocumentList * docList = getCodeDocumentList ( ) ;
for ( CodeDocument * codeDoc = docList - > first ( ) ; codeDoc ; codeDoc = docList - > next ( ) )
codeDoc - > saveToXMI ( doc , docElement ) ;
root . appendChild ( docElement ) ;
}
/**
* Initialize this code generator from its parent UMLDoc . When this is called , it will
* ( re - ) generate the list of code documents for this project ( generator ) by checking
* for new objects / attributes which have been added or changed in the documnet . One or more
* CodeDocuments will be created / overwritten / amended as is appropriate for the given language .
*
* In this ' generic ' version a ClassifierCodeDocument will exist for each and
* every classifier that exists in our UMLDoc . IF when this is called , a code document
* doesn ' t exist for the given classifier , then we will created and add a new code
* document to our generator .
*
* IF you want to add non - classifier related code documents at this step ,
* you will need to overload this method in the appropriate
* code generatator ( see JavaCodeGenerator for an example of this ) .
*/
void CodeGenerator : : initFromParentDocument ( ) {
// Walk through the document converting classifiers into
// classifier code documents as needed (e.g only if doesn't exist)
UMLClassifierList concepts = UMLApp : : app ( ) - > getDocument ( ) - > getClassesAndInterfaces ( ) ;
for ( UMLClassifier * c = concepts . first ( ) ; c ; c = concepts . next ( ) )
{
// Doesn't exist? Then build one.
CodeDocument * codeDoc = findCodeDocumentByClassifier ( c ) ;
if ( ! codeDoc )
{
codeDoc = newClassifierCodeDocument ( c ) ;
addCodeDocument ( codeDoc ) ; // this will also add a unique tag to the code document
}
}
}
/**
* Force a synchronize of this code generator , and its present contents , to that of the parent UMLDocument .
* " UserGenerated " code will be preserved , but Autogenerated contents will be updated / replaced
* or removed as is apppropriate .
*/
void CodeGenerator : : syncCodeToDocument ( ) {
for ( CodeDocument * doc = m_codedocumentVector . first ( ) ; doc ; doc = m_codedocumentVector . next ( ) )
doc - > synchronize ( ) ;
}
// in this 'vanilla' version, we only worry about adding classifier
// documents
void CodeGenerator : : checkAddUMLObject ( UMLObject * obj ) {
if ( ! obj )
return ;
UMLClassifier * c = dynamic_cast < UMLClassifier * > ( obj ) ;
if ( c ) {
CodeDocument * cDoc = newClassifierCodeDocument ( c ) ;
addCodeDocument ( cDoc ) ;
}
}
void CodeGenerator : : checkRemoveUMLObject ( UMLObject * obj )
{
if ( ! obj )
return ;
UMLClassifier * c = dynamic_cast < UMLClassifier * > ( obj ) ;
if ( c ) {
ClassifierCodeDocument * cDoc = ( ClassifierCodeDocument * ) findCodeDocumentByClassifier ( c ) ;
if ( cDoc )
removeCodeDocument ( cDoc ) ;
}
}
/**
* @ return CodeDocument
* @ param classifier
*/
CodeDocument * CodeGenerator : : findCodeDocumentByClassifier ( UMLClassifier * classifier ) {
return findCodeDocumentByID ( ID2STR ( classifier - > getID ( ) ) ) ;
}
/**
* Write out all code documents to file as appropriate .
*/
void CodeGenerator : : writeCodeToFile ( )
{
writeListedCodeDocsToFile ( & m_codedocumentVector ) ;
}
void CodeGenerator : : writeCodeToFile ( UMLClassifierList & concepts ) {
CodeDocumentList docs ;
docs . setAutoDelete ( false ) ;
for ( UMLClassifier * concept = concepts . first ( ) ; concept ; concept = concepts . next ( ) )
{
CodeDocument * doc = findCodeDocumentByClassifier ( concept ) ;
if ( doc )
docs . append ( doc ) ;
}
writeListedCodeDocsToFile ( & docs ) ;
}
// Main method. Will write out passed code documents to file as appropriate.
void CodeGenerator : : writeListedCodeDocsToFile ( CodeDocumentList * docs ) {
// iterate thru all code documents
for ( CodeDocument * doc = docs - > first ( ) ; doc ; doc = docs - > next ( ) )
{
// we need this so we know when to emit a 'codeGenerated' signal
ClassifierCodeDocument * cdoc = dynamic_cast < ClassifierCodeDocument * > ( doc ) ;
bool codeGenSuccess = false ;
// we only write the document, if so requested
if ( doc - > getWriteOutCode ( ) )
{
TQString filename = findFileName ( doc ) ;
// check that we may open that file for writing
TQFile file ;
if ( openFile ( file , filename ) ) {
TQTextStream stream ( & file ) ;
stream < < doc - > toString ( ) < < endl ;
file . close ( ) ;
codeGenSuccess = true ; // we wrote the code OK
} else {
kWarning ( ) < < " Cannot open file : " < < filename < < " for writing " < < endl ;
}
}
if ( cdoc )
emit codeGenerated ( cdoc - > getParentClassifier ( ) , codeGenSuccess ) ;
}
}
/**
* Create a new Code document belonging to this package .
* @ return CodeDocument
*/
CodeDocument * CodeGenerator : : newCodeDocument ( ) {
CodeDocument * newCodeDoc = new CodeDocument ( ) ;
return newCodeDoc ;
}
/**
* @ return TQString
* @ param file
*/
TQString CodeGenerator : : getHeadingFile ( const TQString & file ) {
return UMLApp : : app ( ) - > getCommonPolicy ( ) - > getHeadingFile ( file ) ;
}
/**
* @ return TQString
* @ param codeDoc
* @ param name
*/
TQString CodeGenerator : : overwritableName ( const TQString & name , const TQString & extension ) {
CodeGenerationPolicy * pol = UMLApp : : app ( ) - > getCommonPolicy ( ) ;
TQDir outputDirectory = pol - > getOutputDirectory ( ) ;
TQString filename = name + extension ;
if ( ! outputDirectory . exists ( filename ) ) {
return filename ;
}
int suffix ;
OverwriteDialogue overwriteDialog ( name , outputDirectory . absPath ( ) ,
m_applyToAllRemaining , kapp - > mainWidget ( ) ) ;
switch ( pol - > getOverwritePolicy ( ) ) { //if it exists, check the OverwritePolicy we should use
case CodeGenerationPolicy : : Ok : //ok to overwrite file
filename = name + extension ;
break ;
case CodeGenerationPolicy : : Ask : //ask if we can overwrite
switch ( overwriteDialog . exec ( ) ) {
case KDialogBase : : Yes : //overwrite file
if ( overwriteDialog . applyToAllRemaining ( ) ) {
pol - > setOverwritePolicy ( CodeGenerationPolicy : : Ok ) ;
filename = name + extension ;
} else {
m_applyToAllRemaining = false ;
}
break ;
case KDialogBase : : No : //generate similar name
suffix = 1 ;
while ( 1 ) {
filename = name + " __ " + TQString : : number ( suffix ) + extension ;
if ( ! outputDirectory . exists ( filename ) )
break ;
suffix + + ;
}
if ( overwriteDialog . applyToAllRemaining ( ) ) {
pol - > setOverwritePolicy ( CodeGenerationPolicy : : Never ) ;
} else {
m_applyToAllRemaining = false ;
}
break ;
case KDialogBase : : Cancel : //don't output anything
if ( overwriteDialog . applyToAllRemaining ( ) ) {
pol - > setOverwritePolicy ( CodeGenerationPolicy : : Cancel ) ;
} else {
m_applyToAllRemaining = false ;
}
return TQString ( ) ;
break ;
}
break ;
case CodeGenerationPolicy : : Never : //generate similar name
suffix = 1 ;
while ( 1 ) {
filename = name + " __ " + TQString : : number ( suffix ) + extension ;
if ( ! outputDirectory . exists ( filename ) )
break ;
suffix + + ;
}
break ;
case CodeGenerationPolicy : : Cancel : //don't output anything
return TQString ( ) ;
break ;
}
return filename ;
}
/**
* @ return bool
* @ param file
* @ param name
*/
bool CodeGenerator : : openFile ( TQFile & file , const TQString & fileName ) {
//open files for writing.
if ( fileName . isEmpty ( ) ) {
kWarning ( ) < < " cannot find a file name " < < endl ;
return false ;
} else {
TQDir outputDirectory = UMLApp : : app ( ) - > getCommonPolicy ( ) - > getOutputDirectory ( ) ;
file . setName ( outputDirectory . absFilePath ( fileName ) ) ;
if ( ! file . open ( IO_WriteOnly ) ) {
KMessageBox : : sorry ( 0 , i18n ( " Cannot open file %1 for writing. Please make sure the folder exists and you have permissions to write to it. " ) . tqarg ( file . name ( ) ) , i18n ( " Cannot Open File " ) ) ;
return false ;
}
return true ;
}
}
/**
* @ return TQString
* @ param name
*/
TQString CodeGenerator : : cleanName ( const TQString & name ) {
TQString retval = name ;
retval . replace ( TQRegExp ( " \\ W " ) , " _ " ) ;
return retval ;
}
TQString CodeGenerator : : findFileName ( CodeDocument * codeDocument ) {
//else, determine the "natural" file name
TQString name ;
// Get the path name
TQString path = codeDocument - > getPath ( ) ;
// if path is given add this as a directory to the file name
if ( ! path . isEmpty ( ) ) {
path . replace ( TQRegExp ( " :: " ) , " / " ) ; // Simple hack!
name = path + ' / ' + codeDocument - > getFileName ( ) ;
path = ' / ' + path ;
} else {
name = codeDocument - > getFileName ( ) ;
}
// Convert all "::" to "/" : Platform-specific path separator
name . replace ( TQRegExp ( " :: " ) , " / " ) ; // Simple hack!
// if a path name exists check the existence of the path directory
if ( ! path . isEmpty ( ) ) {
TQDir outputDirectory = UMLApp : : app ( ) - > getCommonPolicy ( ) - > getOutputDirectory ( ) ;
TQDir pathDir ( outputDirectory . absPath ( ) + path ) ;
// does our complete output directory exist yet? if not, try to create it
if ( ! pathDir . exists ( ) )
{
// ugh. dir separator here is UNIX specific..
TQStringList dirs = TQStringList : : split ( " / " , pathDir . absPath ( ) ) ;
TQString currentDir = " " ;
TQStringList : : iterator end ( dirs . end ( ) ) ;
for ( TQStringList : : iterator dir ( dirs . begin ( ) ) ; dir ! = end ; + + dir )
{
currentDir + = ' / ' + * dir ;
if ( ! ( pathDir . exists ( currentDir )
| | pathDir . mkdir ( currentDir ) ) )
{
KMessageBox : : error ( 0 , i18n ( " Cannot create the folder: \n " ) +
pathDir . absPath ( ) + i18n ( " \n Please check the access rights " ) ,
i18n ( " Cannot Create Folder " ) ) ;
return NULL ;
}
}
}
}
name . simplifyWhiteSpace ( ) ;
name . replace ( TQRegExp ( " " ) , " _ " ) ;
return overwritableName ( name , codeDocument - > getFileExtension ( ) ) ;
}
void CodeGenerator : : findObjectsRelated ( UMLClassifier * c , UMLPackageList & cList ) {
UMLPackage * temp ;
UMLAssociationList associations = c - > getAssociations ( ) ;
for ( UMLAssociation * a = associations . first ( ) ; a ; a = associations . next ( ) ) {
temp = 0 ;
switch ( a - > getAssocType ( ) ) {
case Uml : : at_Generalization :
case Uml : : at_Realization :
// only the "b" end is seen by the "a" end, not other way around
{
UMLObject * objB = a - > getObject ( Uml : : B ) ;
if ( objB ! = c )
temp = ( UMLPackage * ) objB ;
}
break ;
case Uml : : at_Dependency :
case Uml : : at_UniAssociation :
{
UMLObject * objA = a - > getObject ( Uml : : A ) ;
UMLObject * objB = a - > getObject ( Uml : : B ) ;
if ( objA = = c )
temp = static_cast < UMLPackage * > ( objB ) ;
}
break ;
case Uml : : at_Aggregation :
case Uml : : at_Composition :
case Uml : : at_Association :
{
UMLObject * objA = a - > getObject ( Uml : : A ) ;
UMLObject * objB = a - > getObject ( Uml : : B ) ;
if ( objA = = c & & objB - > getBaseType ( ) ! = Uml : : ot_Datatype )
temp = static_cast < UMLPackage * > ( objB ) ;
}
break ;
default : /* all others.. like for state diagrams..we currently don't use */
break ;
}
// now add in list ONLY if its not already there
if ( temp & & ! cList . containsRef ( temp ) )
cList . append ( temp ) ;
}
//operations
UMLOperationList opl ( c - > getOpList ( ) ) ;
for ( UMLOperation * op = opl . first ( ) ; op ; op = opl . next ( ) ) {
temp = 0 ;
//check return value
temp = ( UMLClassifier * ) op - > getType ( ) ;
if ( temp & & temp - > getBaseType ( ) ! = Uml : : ot_Datatype & & ! cList . containsRef ( temp ) )
cList . append ( temp ) ;
//check parameters
UMLAttributeList atl = op - > getParmList ( ) ;
for ( UMLAttribute * at = atl . first ( ) ; at ; at = atl . next ( ) ) {
temp = ( UMLClassifier * ) at - > getType ( ) ;
if ( temp & & temp - > getBaseType ( ) ! = Uml : : ot_Datatype & & ! cList . containsRef ( temp ) )
cList . append ( temp ) ;
}
}
//attributes
if ( ! c - > isInterface ( ) ) {
UMLAttributeList atl = c - > getAttributeList ( ) ;
for ( UMLAttribute * at = atl . first ( ) ; at ; at = atl . next ( ) ) {
temp = 0 ;
temp = ( UMLClassifier * ) at - > getType ( ) ;
if ( temp & & temp - > getBaseType ( ) ! = Uml : : ot_Datatype & & ! cList . containsRef ( temp ) )
cList . append ( temp ) ;
}
}
}
/**
* Format an output document .
* @ return TQString
* @ param text
* @ param lineprefix
* @ param linewidth
*/
TQString CodeGenerator : : formatDoc ( const TQString & text , const TQString & linePrefix , int lineWidth ) {
TQString output ;
const TQString endLine = UMLApp : : app ( ) - > getCommonPolicy ( ) - > getNewLineEndingChars ( ) ;
TQStringList lines = TQStringList : : split ( endLine , text ) ;
for ( TQStringList : : ConstIterator lit = lines . begin ( ) ; lit ! = lines . end ( ) ; + + lit ) {
TQString input = * lit ;
input . remove ( TQRegExp ( " \\ s+$ " ) ) ;
if ( input . length ( ) < ( uint ) lineWidth ) {
output + = linePrefix + input + endLine ;
continue ;
}
int index ;
while ( ( index = input . findRev ( " " , lineWidth ) ) > = 0 ) {
output + = linePrefix + input . left ( index ) + endLine ; // add line
input . remove ( 0 , index + 1 ) ; //and remove processed string, including
// white space
}
if ( ! input . isEmpty ( ) )
output + = linePrefix + input + endLine ;
}
return output ;
}
void CodeGenerator : : initFields ( ) {
m_document = UMLApp : : app ( ) - > getDocument ( ) ;
m_codeDocumentDictionary . setAutoDelete ( false ) ;
m_codedocumentVector . setAutoDelete ( false ) ;
m_applyToAllRemaining = true ;
lastIDIndex = 0 ;
// initial population of our project generator
// CANT Be done here because we would call pure virtual method
// of newClassifierDocument (bad!).
// We should only call from the child
// initFromParentDocument();
}
void CodeGenerator : : connect_newcodegen_slots ( ) {
UMLDoc * doc = UMLApp : : app ( ) - > getDocument ( ) ;
connect ( doc , TQT_SIGNAL ( sigObjectCreated ( UMLObject * ) ) ,
this , TQT_SLOT ( checkAddUMLObject ( UMLObject * ) ) ) ;
connect ( doc , TQT_SIGNAL ( sigObjectRemoved ( UMLObject * ) ) ,
this , TQT_SLOT ( checkRemoveUMLObject ( UMLObject * ) ) ) ;
CodeGenerationPolicy * commonPolicy = UMLApp : : app ( ) - > getCommonPolicy ( ) ;
connect ( commonPolicy , TQT_SIGNAL ( modifiedCodeContent ( ) ) ,
this , TQT_SLOT ( syncCodeToDocument ( ) ) ) ;
}
// these are utility methods for accessing the default
// code gen policy object and should go away when we
// finally implement the CodeGenDialog class -b.t.
void CodeGenerator : : setForceDoc ( bool f ) {
UMLApp : : app ( ) - > getCommonPolicy ( ) - > setCodeVerboseDocumentComments ( f ) ;
}
bool CodeGenerator : : forceDoc ( ) const {
return UMLApp : : app ( ) - > getCommonPolicy ( ) - > getCodeVerboseDocumentComments ( ) ;
}
void CodeGenerator : : setForceSections ( bool f ) {
UMLApp : : app ( ) - > getCommonPolicy ( ) - > setCodeVerboseSectionComments ( f ) ;
}
bool CodeGenerator : : forceSections ( ) const {
return UMLApp : : app ( ) - > getCommonPolicy ( ) - > getCodeVerboseSectionComments ( ) ;
}
TQStringList CodeGenerator : : defaultDatatypes ( ) {
return TQStringList ( ) ;
//empty by default, override in your code generator
}
bool CodeGenerator : : isReservedKeyword ( const TQString & keyword ) {
const TQStringList keywords = reservedKeywords ( ) ;
return keywords . contains ( keyword ) ;
}
const TQStringList CodeGenerator : : reservedKeywords ( ) const {
static TQStringList emptyList ;
return emptyList ;
}
void CodeGenerator : : createDefaultStereotypes ( ) {
//empty by default, override in your code generator
//e.g. m_document->createDefaultStereotypes("constructor");
}
# include "codegenerator.moc"