diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | bd9e6617827818fd043452c08c606f07b78014a0 (patch) | |
tree | 425bb4c3168f9c02f10150f235d2cb998dcc6108 /umbrello/umbrello/classifiercodedocument.cpp | |
download | tdesdk-bd9e6617827818fd043452c08c606f07b78014a0.tar.gz tdesdk-bd9e6617827818fd043452c08c606f07b78014a0.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdesdk@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'umbrello/umbrello/classifiercodedocument.cpp')
-rw-r--r-- | umbrello/umbrello/classifiercodedocument.cpp | 742 |
1 files changed, 742 insertions, 0 deletions
diff --git a/umbrello/umbrello/classifiercodedocument.cpp b/umbrello/umbrello/classifiercodedocument.cpp new file mode 100644 index 00000000..a2d2f9fc --- /dev/null +++ b/umbrello/umbrello/classifiercodedocument.cpp @@ -0,0 +1,742 @@ +/*************************************************************************** + * * + * 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 "classifiercodedocument.h" + +// qt/kde includes +#include <kdebug.h> +#include <qregexp.h> + +// local includes +#include "association.h" +#include "attribute.h" +#include "operation.h" +#include "classifierlistitem.h" +#include "classifier.h" +#include "codegenerator.h" +#include "uml.h" +#include "umldoc.h" +#include "umlrole.h" +#include "umlattributelist.h" +#include "umloperationlist.h" +#include "codegenerators/codegenfactory.h" + +// Constructors/Destructors +// + +ClassifierCodeDocument::ClassifierCodeDocument ( UMLClassifier * parent ) +{ + init (parent); +} + +ClassifierCodeDocument::~ClassifierCodeDocument ( ) +{ + for (CodeClassFieldListIt ccflit(m_classfieldVector); ccflit.current(); ++ccflit) + { + CodeClassField * cf = ccflit.current(); + delete cf; + } + m_classfieldVector.clear(); +} + +// +// Methods +// + + +// Accessor methods +// + +/** get a list of codeclassifier objects held by this classifiercodedocument that meet the passed criteria. + */ +CodeClassFieldList ClassifierCodeDocument::getSpecificClassFields (CodeClassField::ClassFieldType cfType) +{ + CodeClassFieldList list; + for (CodeClassFieldListIt ccflit(m_classfieldVector); ccflit.current(); ++ccflit) + { + CodeClassField * cf = ccflit.current(); + if (cf->getClassFieldType() == cfType) + list.append(cf); + } + return list; +} + +/** get a list of codeclassifier objects held by this classifiercodedocument that meet the passed criteria. + */ +CodeClassFieldList ClassifierCodeDocument::getSpecificClassFields (CodeClassField::ClassFieldType cfType, bool isStatic) +{ + CodeClassFieldList list; + list.setAutoDelete(false); + for (CodeClassFieldListIt ccflit(m_classfieldVector); ccflit.current(); ++ccflit) + { + CodeClassField * cf = ccflit.current(); + if (cf->getClassFieldType() == cfType && cf->getStatic() == isStatic) + list.append(cf); + } + return list; +} + +/** get a list of codeclassifier objects held by this classifiercodedocument that meet the passed criteria. + */ +CodeClassFieldList ClassifierCodeDocument::getSpecificClassFields (CodeClassField::ClassFieldType cfType, Uml::Visibility visibility) +{ + CodeClassFieldList list; + list.setAutoDelete(false); + for (CodeClassFieldListIt ccflit(m_classfieldVector); ccflit.current(); ++ccflit) + { + CodeClassField * cf = ccflit.current(); + if (cf->getClassFieldType() == cfType && cf->getVisibility() == visibility) + list.append(cf); + } + return list; +} + +/** get a list of codeclassifier objects held by this classifiercodedocument that meet the passed criteria. + */ +CodeClassFieldList ClassifierCodeDocument::getSpecificClassFields (CodeClassField::ClassFieldType cfType, bool isStatic, Uml::Visibility visibility) +{ + CodeClassFieldList list; + list.setAutoDelete(false); + for (CodeClassFieldListIt ccflit(m_classfieldVector); ccflit.current(); ++ccflit) + { + CodeClassField * cf = ccflit.current(); + if (cf->getClassFieldType() == cfType && cf->getVisibility() == visibility && cf->getStatic() == isStatic ) + list.append(cf); + } + return list; +} + +// do we have accessor methods for lists of objects? +// (as opposed to lists of primitive types like 'int' or 'float', etc) +bool ClassifierCodeDocument::hasObjectVectorClassFields() { + for (CodeClassFieldListIt ccflit(m_classfieldVector); ccflit.current(); ++ccflit) + { + CodeClassField * cf = ccflit.current(); + if(cf->getClassFieldType() != CodeClassField::Attribute) + { + UMLRole * role = dynamic_cast<UMLRole*>(cf->getParentObject()); + QString multi = role->getMultiplicity(); + if ( + multi.contains(QRegExp("[23456789\\*]")) || + multi.contains(QRegExp("1\\d")) + ) + return true; + } + } + return false; +} + +bool ClassifierCodeDocument::hasClassFields() { + if(m_classfieldVector.count() > 0 ) + return true; + return false; +} + +/** + * Tell if one or more codeclassfields are derived from associations. + */ +bool ClassifierCodeDocument::hasAssociationClassFields() { + CodeClassFieldList list = getSpecificClassFields(CodeClassField::Attribute); + return (m_classfieldVector.count() - list.count()) > 0 ? true : false; +} + +/** + * Tell if one or more codeclassfields are derived from attributes. + */ +bool ClassifierCodeDocument::hasAttributeClassFields() { + CodeClassFieldList list = getSpecificClassFields(CodeClassField::Attribute); + return list.count() > 0 ? true : false; +} + +/** + * Add a CodeClassField object to the m_classfieldVector List + * @return boolean true if successful in adding + */ +// We DON'T add methods of the code classfield here because we need to allow +// the codegenerator writer the liberty to organize their document as they desire. +bool ClassifierCodeDocument::addCodeClassField ( CodeClassField * add_object ) { + UMLObject * umlobj = add_object->getParentObject(); + if(!(m_classFieldMap.contains(umlobj))) + { + m_classfieldVector.append(add_object); + m_classFieldMap.insert(umlobj,add_object); + + return true; + } + return false; +} + +// this is a slot..should only be called from a signal +void ClassifierCodeDocument::addAttributeClassField (UMLClassifierListItem *obj, bool syncToParentIfAdded) { + UMLAttribute *at = (UMLAttribute*)obj; + CodeClassField * cf = CodeGenFactory::newCodeClassField(this, at); + if(cf) + if (addCodeClassField(cf) && syncToParentIfAdded) + updateContent(); +} + +/** + * Remove a CodeClassField object from m_classfieldVector List + */ +bool ClassifierCodeDocument::removeCodeClassField ( CodeClassField * remove_object ) { + UMLObject * umlobj = remove_object->getParentObject(); + if(m_classFieldMap.contains(umlobj)) + { + if (m_classfieldVector.removeRef(remove_object)) + { + // remove from our classfield map + m_classFieldMap.remove(umlobj); + delete remove_object; + return true; + } + } + return false; +} + +void ClassifierCodeDocument::removeAttributeClassField(UMLClassifierListItem *obj) +{ + CodeClassField * remove_object = m_classFieldMap[obj]; + if(remove_object) + removeCodeClassField(remove_object); +} + +void ClassifierCodeDocument::removeAssociationClassField (UMLAssociation *assoc ) +{ + + // the object could be either (or both!) role a or b. We should check + // both parts of the association. + CodeClassField * remove_object = m_classFieldMap[assoc->getUMLRole(Uml::A)]; + if(remove_object) + removeCodeClassField(remove_object); + + // check role b + remove_object = m_classFieldMap[assoc->getUMLRole(Uml::B)]; + if(remove_object) + removeCodeClassField(remove_object); + +} + +/** + * Get the list of CodeClassField objects held by m_classfieldVector + * @return CodeClassFieldList list of CodeClassField objects held by + * m_classfieldVector + */ +CodeClassFieldList * ClassifierCodeDocument::getCodeClassFieldList ( ) { + return &m_classfieldVector; +} + +/** + * Get the value of m_parentclassifier + * @return the value of m_parentclassifier + */ +UMLClassifier * ClassifierCodeDocument::getParentClassifier ( ) { + return m_parentclassifier; +} + +/** + * @return QPtrList<CodeOperation> + */ +QPtrList<CodeOperation> ClassifierCodeDocument::getCodeOperations ( ) { + + QPtrList<CodeOperation> list; + list.setAutoDelete(false); + + TextBlockList * tlist = getTextBlockList(); + for (TextBlock *tb = tlist->first(); tb; tb=tlist->next()) + { + CodeOperation * cop = dynamic_cast<CodeOperation*>(tb); + if(cop) + list.append(cop); + } + return list; +} + +/** + * @param o The Operation to add + */ +void ClassifierCodeDocument::addOperation (UMLClassifierListItem * o) { + UMLOperation *op = dynamic_cast<UMLOperation*>(o); + if (op == NULL) { + kError() << "ClassifierCodeDocument::addOperation: arg is not a UMLOperation" + << endl; + } + QString tag = CodeOperation::findTag(op); + CodeOperation * codeOp = dynamic_cast<CodeOperation*>(findTextBlockByTag(tag, true)); + bool createdNew = false; + + // create the block, if it doesn't already exist + if(!codeOp) + { + codeOp = CodeGenFactory::newCodeOperation(this, op); + createdNew = true; + } + + // now try to add it. This may fail because it (or a block with + // the same tag) is already in the document somewhere. IF we + // created this new, then we need to delete our object. + if(!addCodeOperation(codeOp)) // wont add if already present + if(createdNew) + delete codeOp; + +} + +/** + * @param op + */ +void ClassifierCodeDocument::removeOperation (UMLClassifierListItem * op ) { + + QString tag = CodeOperation::findTag((UMLOperation*)op); + TextBlock *tb = findTextBlockByTag(tag, true); + if(tb) + { + if(removeTextBlock(tb)) // wont add if already present + delete tb; // delete unused operations + else + kError()<<"Cant remove CodeOperation from ClassCodeDocument!"<<endl; + + } + else + kError()<<"Cant Find codeOperation for deleted operation!"<<endl; +} + +// Other methods +// + +void ClassifierCodeDocument::addCodeClassFieldMethods(CodeClassFieldList &list ) +{ + + for (CodeClassFieldListIt ccflit(list); ccflit.current(); ++ccflit) + { + CodeClassField * field = ccflit.current(); + CodeAccessorMethodList list = field->getMethodList(); + CodeAccessorMethod * method; + for (CodeAccessorMethodListIt it(list); (method = it.current()) != NULL; ++it) + { + /* + QString tag = method->getTag(); + if(tag.isEmpty()) + { + tag = getUniqueTag(); + method->setTag(tag); + } + */ + addTextBlock(method); // wont add if already exists in document, will add a tag if missing; + + } + + } + +} + +// add declaration blocks for the passed classfields +void ClassifierCodeDocument::declareClassFields (CodeClassFieldList & list , + CodeGenObjectWithTextBlocks * parent ) +{ + + for (CodeClassFieldListIt ccflit(list); ccflit.current(); ++ccflit) + { + CodeClassField * field = ccflit.current(); + CodeClassFieldDeclarationBlock * declBlock = field->getDeclarationCodeBlock(); + + /* + // if it has a tag, check + if(!declBlock->getTag().isEmpty()) + { + // In C++, because we may shift the declaration to a different parent + // block for a change in scope, we need to track down any pre-existing + // location, and remove FIRST before adding to new parent + CodeGenObjectWithTextBlocks * oldParent = findParentObjectForTaggedTextBlock (declBlock->getTag()); + if(oldParent) { + if(oldParent != parent) + oldParent->removeTextBlock(declBlock); + } + } + */ + + parent->addTextBlock(declBlock); // wont add it IF its already present. Will give it a tag if missing + + } +} + +bool ClassifierCodeDocument::parentIsClass() { + return (m_parentclassifier->getBaseType() == Uml::ot_Class); +} + +bool ClassifierCodeDocument::parentIsInterface() { + return (m_parentclassifier->getBaseType() == Uml::ot_Interface); +} + +/** + * Init from a UMLClassifier object. + * @param classifier + * @param package + */ +void ClassifierCodeDocument::init (UMLClassifier * c ) +{ + + m_parentclassifier = c; + m_classfieldVector.setAutoDelete(false); + + updateHeader(); + syncNamesToParent(); + // initCodeClassFields(); // cant call here?..newCodeClassField is pure virtual + + // slots + if (parentIsClass()) { + connect(c,SIGNAL(attributeAdded(UMLClassifierListItem*)),this,SLOT(addAttributeClassField(UMLClassifierListItem*))); + connect(c,SIGNAL(attributeRemoved(UMLClassifierListItem*)),this,SLOT(removeAttributeClassField(UMLClassifierListItem*))); + } + + connect(c,SIGNAL(sigAssociationEndAdded(UMLAssociation*)),this,SLOT(addAssociationClassField(UMLAssociation*))); + connect(c,SIGNAL(sigAssociationEndRemoved(UMLAssociation*)),this,SLOT(removeAssociationClassField(UMLAssociation*))); + connect(c,SIGNAL(operationAdded(UMLClassifierListItem*)),this,SLOT(addOperation(UMLClassifierListItem*))); + connect(c,SIGNAL(operationRemoved(UMLClassifierListItem*)),this,SLOT(removeOperation(UMLClassifierListItem*))); + connect(c,SIGNAL(modified()),this,SLOT(syncToParent())); + +} + +// IF the classifier object is modified, this will get called. +// @todo we cannot make this virtual as long as the +// ClassifierCodeDocument constructor calls it because that gives +// a call-before-construction error. +// Example of the problem: CPPSourceCodeDocument reimplementing syncNamesToParent() +// CPPCodeGenerator::initFromParentDocument() +// CodeDocument * codeDoc = new CPPSourceCodeDocument(c); +// CPPSourceCodeDocument::CPPSourceCodeDocument(UMLClassifier * concept) +// : ClassifierCodeDocument(concept) +// ClassifierCodeDocument::ClassifierCodeDocument(concept) +// init(concept); +// syncNamesToParent(); +// dispatches to CPPSourceCodeDocument::syncNamesToParent() +// but that object is not yet constructed. +// +void ClassifierCodeDocument::syncNamesToParent( ) { + QString fileName = CodeGenerator::cleanName(getParentClassifier()->getName()); + if (!UMLApp::app()->activeLanguageIsCaseSensitive()) { + // @todo let the user decide about mixed case file names (codegen setup menu) + fileName = fileName.lower(); + } + setFileName(fileName); + setPackage(m_parentclassifier->getUMLPackage()); +} + +void ClassifierCodeDocument::synchronize( ) { + + updateHeader(); // doing this insures time/date stamp is at the time of this call + syncNamesToParent(); + updateContent(); + syncClassFields(); + updateOperations(); + +} + +void ClassifierCodeDocument::syncClassFields( ) +{ + for (CodeClassFieldListIt ccflit(m_classfieldVector); ccflit.current(); ++ccflit) + { + CodeClassField * cf = ccflit.current(); + cf->synchronize(); + } +} + +void ClassifierCodeDocument::updateOperations( ) { + + UMLOperationList opList(getParentClassifier()->getOpList()); + for (UMLOperation *op = opList.first(); op; op = opList.next()) + { + QString tag = CodeOperation::findTag(op); + CodeOperation * codeOp = dynamic_cast<CodeOperation*>(findTextBlockByTag(tag, true)); + bool createdNew = false; + + if(!codeOp) + { + codeOp = CodeGenFactory::newCodeOperation(this, op); + createdNew = true; + } + + // now try to add it. This may fail because it (or a block with + // the same tag) is already in the document somewhere. IF we + // created this new, then we need to delete our object. + if(!addCodeOperation(codeOp)) // wont add if already present + if(createdNew) + delete codeOp; + + // synchronize all non-new operations + if(!createdNew) + codeOp->syncToParent(); + } + +} + +void ClassifierCodeDocument::syncToParent( ) { + synchronize(); +} + +/** + * add codeclassfields to this classifiercodedocument. IF a codeclassfield + * already exists, it is not added. + */ +void ClassifierCodeDocument::initCodeClassFields ( ) { + + UMLClassifier * c = getParentClassifier(); + // first, do the code classifields that arise from attributes + if (parentIsClass()) { + UMLAttributeList alist = c->getAttributeList(); + for(UMLAttribute * at = alist.first(); at; at = alist.next()) + { + CodeClassField * field = CodeGenFactory::newCodeClassField(this, at); + addCodeClassField(field); + } + + } + + // now, do the code classifields that arise from associations + UMLAssociationList ap = c->getSpecificAssocs(Uml::at_Association); + UMLAssociationList ag = c->getAggregations(); + UMLAssociationList ac = c->getCompositions(); + UMLAssociationList selfAssoc = c->getSpecificAssocs(Uml::at_Association_Self); + + updateAssociationClassFields(ap); + updateAssociationClassFields(ag); + updateAssociationClassFields(ac); + updateAssociationClassFields(selfAssoc); + +} + +void ClassifierCodeDocument::updateAssociationClassFields ( UMLAssociationList &assocList ) +{ + CodeClassFieldList list; + for(UMLAssociation * a=assocList.first(); a; a=assocList.next()) + addAssociationClassField(a, false); // syncToParent later +} + +void ClassifierCodeDocument::addAssociationClassField (UMLAssociation * a, bool syncToParentIfAdded) +{ + + Uml::IDType cid = getParentClassifier()->getID(); // so we know who 'we' are + bool printRoleA = false, printRoleB = false, shouldSync = false; + // it may seem counter intuitive, but you want to insert the role of the + // *other* class into *this* class. + if (a->getObjectId(Uml::A) == cid) + printRoleB = true; + + if (a->getObjectId(Uml::B) == cid) + printRoleA = true; + + // grab RoleB decl + if (printRoleB) + { + + UMLRole * role = a->getUMLRole(Uml::B); + if(!m_classFieldMap.contains((UMLObject*)role)) + { + CodeClassField * classfield = CodeGenFactory::newCodeClassField(this, role); + if( addCodeClassField(classfield)) + shouldSync = true; + } + } + + // print RoleA decl + if (printRoleA) + { + UMLRole * role = a->getUMLRole(Uml::A); + if(!m_classFieldMap.contains((UMLObject*)role)) + { + CodeClassField * classfield = CodeGenFactory::newCodeClassField(this, role); + if( addCodeClassField(classfield)) + shouldSync = true; + } + } + + if (shouldSync && syncToParentIfAdded) + syncToParent(); // needed for a slot add + +} + +/** set the class attributes of this object from + * the passed element node. + */ +void ClassifierCodeDocument::setAttributesFromNode ( QDomElement & elem ) +{ + + // NOTE: we DON'T set the parent here as we ONLY get to this point + // IF the parent codegenerator could find a matching parent classifier + // that already has a code document. + + // We FIRST set code class field stuff..check re-linnking with + // accessor methods by looking for our particular child element + QDomNode node = elem.firstChild(); + QDomElement childElem = node.toElement(); + while( !childElem.isNull() ) { + QString tag = childElem.tagName(); + if( tag == "classfields" ) { + // load classfields + loadClassFieldsFromXMI(childElem); + break; + } + node = childElem.nextSibling(); + childElem= node.toElement(); + } + + // call super-class after. THis will populate the text blocks (incl + // the code accessor methods above) as is appropriate + CodeDocument::setAttributesFromNode(elem); + +} + +// look at all classfields currently in document.. match up +// by parent object ID and Role ID (needed for self-association CF's) +CodeClassField * +ClassifierCodeDocument::findCodeClassFieldFromParentID (Uml::IDType id, + int role_id) +{ + for (CodeClassFieldListIt ccflit(m_classfieldVector); ccflit.current(); ++ccflit) + { + CodeClassField * cf = ccflit.current(); + if(role_id == -1) { // attribute-based + if (STR2ID(cf->getID()) == id) + return cf; + } else { // association(role)-based + const Uml::Role_Type r = (Uml::Role_Type)role_id; + UMLRole * role = dynamic_cast<UMLRole *>(cf->getParentObject()); + if(role && STR2ID(cf->getID()) == id && role->getRole() == r) + return cf; + } + } + + // shouldn't happen.. + kError() << "Failed to find codeclassfield for parent uml id:" + << ID2STR(id) << " (role id:" << role_id + << ") Do you have a corrupt classifier code document?" + << endl; + + return (CodeClassField*) NULL; // not found +} + +void ClassifierCodeDocument::loadClassFieldsFromXMI( QDomElement & elem) { + + QDomNode node = elem.firstChild(); + QDomElement childElem = node.toElement(); + while( !childElem.isNull() ) { + QString nodeName = childElem.tagName(); + if( nodeName == "codeclassfield") + { + QString id = childElem.attribute("parent_id","-1"); + int role_id = childElem.attribute("role_id","-1").toInt(); + CodeClassField * cf = findCodeClassFieldFromParentID(STR2ID(id), role_id); + if(cf) + { + // Because we just may change the parent object here, + // we need to yank it from the map of umlobjects + m_classFieldMap.remove(cf->getParentObject()); + + // configure from XMI + cf->loadFromXMI(childElem); + + // now add back in + m_classFieldMap.insert(cf->getParentObject(),cf); + + } else + kError()<<" LoadFromXMI: can't load classfield parent_id:"<<id<<" do you have a corrupt savefile?"<<endl; + } + node = childElem.nextSibling(); + childElem= node.toElement(); + } +} + +/** + * Save the XMI representation of this object + */ +void ClassifierCodeDocument::saveToXMI ( QDomDocument & doc, QDomElement & root ) { +#if 0 + // avoid the creation of primitive data type + QString strType; + if (getParentClassifier()->getBaseType() == Uml::ot_Datatype) { + strType = getParentClassifier()->getName(); + // lets get the default code generator to check if it is a primitive data type + // there's a reason to create files for int/boolean and so ? + if (getParentGenerator()->isReservedKeyword(strType)) + return; + } +#endif + QDomElement docElement = doc.createElement( "classifiercodedocument" ); + + setAttributesOnNode(doc, docElement); + + root.appendChild( docElement ); +} + +/** + * load params from the appropriate XMI element node. + */ +void ClassifierCodeDocument::loadFromXMI ( QDomElement & root ) { + + // set attributes/fields + setAttributesFromNode(root); + + // now sync our doc, needed? + // synchronize(); +} + +/** set attributes of the node that represents this class + * in the XMI document. + */ +void ClassifierCodeDocument::setAttributesOnNode ( QDomDocument & doc, QDomElement & docElement) +{ + + // do super-class first + CodeDocument::setAttributesOnNode(doc, docElement); + + // cache local attributes/fields + docElement.setAttribute("parent_class", ID2STR(getParentClassifier()->getID())); + + // (code) class fields + // which we will store in its own separate child node block + QDomElement fieldsElement = doc.createElement( "classfields" ); + for (CodeClassFieldListIt ccflit(m_classfieldVector); ccflit.current(); ++ccflit) + { + CodeClassField * field = ccflit.current(); + field->saveToXMI(doc, fieldsElement); + } + docElement.appendChild( fieldsElement); + +} + +TextBlock * ClassifierCodeDocument::findCodeClassFieldTextBlockByTag (const QString &tag) +{ + + for (CodeClassFieldListIt ccflit(m_classfieldVector); ccflit.current(); ++ccflit) + { + CodeClassField * cf = ccflit.current(); + CodeClassFieldDeclarationBlock * decl = cf->getDeclarationCodeBlock(); + if(decl && decl->getTag() == tag) + return decl; + // well, if not in the decl block, then in the methods perhaps? + CodeAccessorMethodList mlist = cf->getMethodList(); + CodeAccessorMethod *m; + for (CodeAccessorMethodListIt it(mlist); (m = it.current()) != NULL; ++it) + if(m->getTag() == tag) + return m; + } + + // if we get here, we failed. + return (TextBlock*) NULL; + +} + + +#include "classifiercodedocument.moc" |