Logo Search packages:      
Sourcecode: kdesdk version File versions

classifiercodedocument.cpp

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

/*  This code generated by:
 *      Author : thomas
 *      Date   : Thu Jun 19 2003
 */

#include <kdebug.h>
#include <qregexp.h>

#include "codegenerator.h"
#include "classifiercodedocument.h"
#include "association.h"
#include "attribute.h"
#include "class.h"
#include "interface.h"
#include "umldoc.h"
#include "umlrole.h"
#include "umlattributelist.h"
#include "umloperationlist.h"

// Constructors/Destructors
//

00032 ClassifierCodeDocument::ClassifierCodeDocument ( UMLClassifier * parent , CodeGenerator * gen ) :
       CodeDocument ( gen )
{
      init (parent);
}

00038 ClassifierCodeDocument::~ClassifierCodeDocument ( )
{
      /*FIXME this causes a crash sometimes
      for (CodeClassField * cf = m_classfieldVector.first(); cf; cf = m_classfieldVector.next())  {
             delete cf;
      }
       **** TEMPORARY workaround: */
      m_classfieldVector.clear();
}

//
// Methods
//


// Accessor methods
//

/** get a list of codeclassifier objects held by this classifiercodedocument that meet the passed criteria.
 */
00058 QPtrList<CodeClassField> ClassifierCodeDocument::getSpecificClassFields (CodeClassField::ClassFieldType cfType)
{
      QPtrList<CodeClassField> list;
      for (CodeClassField * cf = m_classfieldVector.first(); cf; cf = m_classfieldVector.next())
            if (cf->getClassFieldType() == cfType)
                  list.append(cf);
      return list;
}

/** get a list of codeclassifier objects held by this classifiercodedocument that meet the passed criteria.
 */
00069 QPtrList<CodeClassField> ClassifierCodeDocument::getSpecificClassFields (CodeClassField::ClassFieldType cfType, bool isStatic)
{
      QPtrList<CodeClassField> list;
      list.setAutoDelete(false);
      for (CodeClassField * cf = m_classfieldVector.first(); cf; cf = m_classfieldVector.next())
            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.
 */
00081 QPtrList<CodeClassField> ClassifierCodeDocument::getSpecificClassFields (CodeClassField::ClassFieldType cfType, Uml::Scope visibility)
{
      QPtrList<CodeClassField> list;
      list.setAutoDelete(false);
      for (CodeClassField * cf = m_classfieldVector.first(); cf; cf = m_classfieldVector.next())
            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.
 */
00093 QPtrList<CodeClassField> ClassifierCodeDocument::getSpecificClassFields (CodeClassField::ClassFieldType cfType, bool isStatic, Uml::Scope visibility)
{
      QPtrList<CodeClassField> list;
      list.setAutoDelete(false);
      for (CodeClassField * cf = m_classfieldVector.first(); cf; cf = m_classfieldVector.next())
            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)
00105 bool ClassifierCodeDocument::hasObjectVectorClassFields() {
      for (CodeClassField * cf = m_classfieldVector.first(); cf; cf = m_classfieldVector.next())
            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;
}

00120 bool ClassifierCodeDocument::hasClassFields() {
      if(m_classfieldVector.count() > 0 )
            return true;
      return false;
}

/**
 * Tell if one or more codeclassfields are derived from associations.
 */
00129 bool ClassifierCodeDocument::hasAssociationClassFields() {
      QPtrList<CodeClassField> list = getSpecificClassFields(CodeClassField::Attribute);
      return (m_classfieldVector.count() - list.count()) > 0 ? true : false;
}

/**
 * Tell if one or more codeclassfields are derived from attributes.
 */
00137 bool ClassifierCodeDocument::hasAttributeClassFields() {
      QPtrList<CodeClassField> list = getSpecificClassFields(CodeClassField::Attribute);
      return list.count() > 0 ? true : false;
}

/**
 * Add a CodeClassField object to the m_classfieldVector List
 * @return boolean value if successfull in adding
 */
// We DONT add methods of the code classfield here because we need to allow
// the codegenerator writer the liberty to organize their document as they desire.
00148 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
00161 void ClassifierCodeDocument::addAttributeClassField (UMLObject *obj, bool syncToParentIfAdded) {
      UMLAttribute *at = (UMLAttribute*)obj;
      CodeClassField * cf = newCodeClassField(at);
      if(cf)
            if (addCodeClassField(cf) && syncToParentIfAdded)
                  updateContent();
}

/**
 * Remove a CodeClassField object from m_classfieldVector List
 */
00172 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(UMLObject *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(A)];
      if(remove_object)
            removeCodeClassField(remove_object);

      // check role b
      remove_object = (*m_classFieldMap)[assoc->getUMLRole(B)];
      if(remove_object)
                  removeCodeClassField(remove_object);

}

/**
 * Get the list of CodeClassField objects held by m_classfieldVector
 * @return QPtrList<CodeClassField> list of CodeClassField objects held by
 * m_classfieldVector
 */
00215 QPtrList<CodeClassField> * ClassifierCodeDocument::getCodeClassFieldList ( ) {
      return &m_classfieldVector;
}

/**
 * Get the value of m_parentclassifier
 * @return the value of m_parentclassifier
 */
00223 UMLClassifier * ClassifierCodeDocument::getParentClassifier ( ) {
      return m_parentclassifier;
}

/**
 * @return      QPtrList<CodeOperation>
 */
00230 QPtrList<CodeOperation> ClassifierCodeDocument::getCodeOperations ( ) {

      QPtrList<CodeOperation> list;
      list.setAutoDelete(false);

      QPtrList<TextBlock> * 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       op
 */
00248 void ClassifierCodeDocument::addOperation (UMLOperation * op ) {

      QString tag = CodeOperation::findTag((UMLOperation*)op);
      CodeOperation * codeOp = dynamic_cast<CodeOperation*>(findTextBlockByTag(tag, true));
      bool createdNew = false;

      // create the block, if it doesnt already exist
      if(!codeOp)
      {
            codeOp = newCodeOperation((UMLOperation*)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
 */
00273 void ClassifierCodeDocument::removeOperation (UMLOperation * op ) {

      QString tag = CodeOperation::findTag((UMLOperation*)op);
      TextBlock *tb = findTextBlockByTag(tag, true);
      if(tb)
      {
            if(removeTextBlock(tb)) // wont add if already present
                  tb->release(); // delete unused operations
            else
                  kdError()<<"Cant remove CodeOperation from ClassCodeDocument!"<<endl;

      }
      else
            kdError()<<"Cant Find codeOperation for deleted operation!"<<endl;
}

// Other methods
//

void ClassifierCodeDocument::addCodeClassFieldMethods(QPtrList<CodeClassField> &list )
{

      for (CodeClassField * field = list.first(); field ; field = list.next())
      {
            QPtrList <CodeAccessorMethod> * list = field->getMethodList();
            for (CodeAccessorMethod * method = list->first(); method; method = list->next())
            {
/*
                  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 (QPtrList<CodeClassField> & list ,
                         CodeGenObjectWithTextBlocks * parent )
{

      for (CodeClassField * field = list.first(); field ; field = list.next())
      {
            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

      }
}

00345 bool ClassifierCodeDocument::parentIsClass() {
      return (m_parentclassifier->getBaseType() == ot_Class);
}

00349 bool ClassifierCodeDocument::parentIsInterface() {
      return (m_parentclassifier->getBaseType() == ot_Interface);
}

/**
 * Init from a UMLClassifier object.
 * @param   classifier
 * @param   package
 */
00358 void ClassifierCodeDocument::init (UMLClassifier * c )
{

      m_parentclassifier = c;
      m_classfieldVector.setAutoDelete(false);
      m_classFieldMap = new QMap<UMLObject *, CodeClassField*>;

      updateHeader();
      syncNamesToParent();
      // initCodeClassFields(); // cant call here?..newCodeClassField is pure virtual

      // slots
      if (parentIsClass())  {
          connect(c,SIGNAL(attributeAdded(UMLObject*)),this,SLOT(addAttributeClassField(UMLObject*)));
          connect(c,SIGNAL(attributeRemoved(UMLObject*)),this,SLOT(removeAttributeClassField(UMLObject*)));
      }

      connect(c,SIGNAL(sigAssociationAdded(UMLAssociation*)),this,SLOT(addAssociationClassField(UMLAssociation*)));
      connect(c,SIGNAL(sigAssociationRemoved(UMLAssociation*)),this,SLOT(removeAssociationClassField(UMLAssociation*)));
      connect(c,SIGNAL(operationAdded(UMLOperation*)),this,SLOT(addOperation(UMLOperation*)));
      connect(c,SIGNAL(operationRemoved(UMLOperation*)),this,SLOT(removeOperation(UMLOperation*)));
      connect(c,SIGNAL(modified()),this,SLOT(syncToParent()));

}

// IF the classifier object is modified, this will get called.
// Possible mods include changing the filename and package
// the classifier has.
void ClassifierCodeDocument::syncNamesToParent( ) {

      setFileName(m_parentclassifier->getName());
      setPackage(m_parentclassifier->getPackage());
}

void ClassifierCodeDocument::synchronize( ) {

      updateHeader(); // doing this insures time/date stamp is at the time of this call
      syncNamesToParent();
      updateContent();
      syncClassFields();
      updateOperations();

}

void ClassifierCodeDocument::syncClassFields( )
{
      QPtrList<CodeClassField> *list = getCodeClassFieldList();
      for(CodeClassField * cf = list->first(); cf; cf=list->next())
            cf->synchronize();
}

void ClassifierCodeDocument::updateOperations( ) {

      UMLOperationList opList(getParentClassifier()->getFilteredOperationsList());
      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 = newCodeOperation((UMLOperation*)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.
 */
00446 void ClassifierCodeDocument::initCodeClassFields ( ) {

      UMLClassifier * c = getParentClassifier();
      // first, do the code classifields that arise from attributes
      if (parentIsClass()) {
            UMLClass * mclass = dynamic_cast<UMLClass*>(c);
            UMLAttributeList* alist = mclass->getFilteredAttributeList();
            for(UMLAttribute * at = alist->first(); at; at = alist->next())
            {
                  CodeClassField * field = newCodeClassField(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 )
{
      QPtrList<CodeClassField> list;
      for(UMLAssociation * a=assocList.first(); a; a=assocList.next())
            addAssociationClassField(a, false); // syncToParent later
}

void ClassifierCodeDocument::addAssociationClassField (UMLAssociation * a, bool syncToParentIfAdded)
{

      int 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->getRoleId(A) == cid)
            printRoleB = true;

      if (a->getRoleId(B) == cid)
            printRoleA = true;

      // grab RoleB decl
      if (printRoleB)
      {

            UMLRole * role = a->getUMLRole(B);
            if(!(m_classFieldMap->contains((UMLObject*)role)))
            {
                  CodeClassField * classfield = newCodeClassField(role);
                  if( addCodeClassField(classfield))
                        shouldSync = true;
            }
      }

      // print RoleA decl
      if (printRoleA)
      {
            UMLRole * role = a->getUMLRole(A);
            if(!(m_classFieldMap->contains((UMLObject*)role)))
            {
                  CodeClassField * classfield = newCodeClassField(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.
 */
00527 void ClassifierCodeDocument::setAttributesFromNode ( QDomElement & elem )
{

      // NOTE: we DONT 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)
00557 CodeClassField * ClassifierCodeDocument::findCodeClassFieldFromParentID (int id, int role_id)
{

      QPtrList<CodeClassField> * list = getCodeClassFieldList();

      if(role_id == -1) { // attribute-based
            for(CodeClassField * cf = list->first(); cf; cf=list->next())
                  if(cf->getID().toInt() == id)
                        return cf;

      } else { // association(role)-based
            // ugh. more underperforming code..if only umlroles where in doc uml obj. list..
            for(CodeClassField * cf = list->first(); cf; cf=list->next())
            {
                  UMLRole * role = dynamic_cast<UMLRole *>(cf->getParentObject());
                  if(role && cf->getID().toInt() == id && role->getRoleID() == role_id)
                        return cf;
            }

      }

      // shouldnt happen..
      kdError()<<"Failed to find codeclassfield for parent uml id:"<<id<<" (role id:"<<role_id<<") Do you have a corrupt classifier code document?"<<endl;

      return (CodeClassField*) NULL; // not found
}

00584 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");
                  QString role_id = childElem.attribute("role_id","-1");
                  CodeClassField * cf = findCodeClassFieldFromParentID(id.toInt(), role_id.toInt());
                  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
                        kdError()<<" 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
 */
00618 void ClassifierCodeDocument::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
      QDomElement docElement = doc.createElement( "classifiercodedocument" );

      setAttributesOnNode(doc, docElement);

      root.appendChild( docElement );
}

/**
 * load params from the appropriate XMI element node.
 */
00629 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.
 */
00641 void ClassifierCodeDocument::setAttributesOnNode ( QDomDocument & doc, QDomElement & docElement)
{

      // do super-class first
      CodeDocument::setAttributesOnNode(doc, docElement);

      // cache local attributes/fields
      docElement.setAttribute("parent_class",QString::number(getParentClassifier()->getID()));

      // (code) class fields
      // which we will store in its own separate child node block
      QDomElement fieldsElement = doc.createElement( "classfields" );
      QPtrList<CodeClassField> * list = getCodeClassFieldList();
      for (CodeClassField * field =list->first(); field; field=list->next())
            field->saveToXMI(doc, fieldsElement);
      docElement.appendChild( fieldsElement);


}

TextBlock * ClassifierCodeDocument::findCodeClassFieldTextBlockByTag (QString tag)
{

      QPtrList<CodeClassField> * list = getCodeClassFieldList();
      for(CodeClassField * cf = list->first(); cf; cf=list->next())
      {
            CodeClassFieldDeclarationBlock * decl = cf->getDeclarationCodeBlock();
            if(decl && decl->getTag() == tag)
                  return decl;
            // well, if not in the decl block, then in the methods perhaps?
            QPtrList<CodeAccessorMethod> * mlist = cf->getMethodList();
            for(CodeAccessorMethod * m = mlist->first(); m; m=mlist->next())
                  if(m->getTag() == tag)
                        return m;
      }

      // if we get here, we failed.
      return (TextBlock*) NULL;

}


#include "classifiercodedocument.moc"

Generated by  Doxygen 1.6.0   Back to index