umbrello API Documentation

codeclassfield.cpp

00001 /***************************************************************************
00002  *                                                                         *
00003  *   This program is free software; you can redistribute it and/or modify  *
00004  *   it under the terms of the GNU General Public License as published by  *
00005  *   the Free Software Foundation; either version 2 of the License, or     *
00006  *   (at your option) any later version.                                   *
00007  *                                                                         *
00008  *   copyright (C) 2004-2006                                               *
00009  *   Umbrello UML Modeller Authors <uml-devel@uml.sf.net>                  *
00010  ***************************************************************************/
00011 
00012 /*  This code generated by:
00013  *      Author : thomas
00014  *      Date   : Fri Jun 20 2003
00015  */
00016 
00017 // own header
00018 #include "codeclassfield.h"
00019 // qt/kde includes
00020 #include <qregexp.h>
00021 #include <kdebug.h>
00022 // app includes
00023 #include "association.h"
00024 #include "classifiercodedocument.h"
00025 #include "codegenerator.h"
00026 #include "attribute.h"
00027 #include "umlobject.h"
00028 #include "umlrole.h"
00029 #include "uml.h"
00030 #include "codegenerators/codegenfactory.h"
00031 
00032 // Constructors/Destructors
00033 //
00034 
00035 CodeClassField::CodeClassField ( ClassifierCodeDocument * doc , UMLRole * role)
00036         : CodeParameter ( doc , (UMLObject*) role)
00037 {
00038 
00039     setParentUMLObject(role);
00040     initFields(true);
00041 
00042 }
00043 
00044 CodeClassField::CodeClassField ( ClassifierCodeDocument * doc , UMLAttribute * attrib)
00045         : CodeParameter ( doc , (UMLObject*) attrib )
00046 {
00047 
00048     setParentUMLObject(attrib);
00049     initFields(true);
00050 
00051 }
00052 
00053 CodeClassField::~CodeClassField ( ) {
00054 
00055     // remove methods from parent document
00056     CodeAccessorMethodList list = m_methodVector;
00057     for(CodeAccessorMethod * m = list.first(); m ; m=list.next())
00058     {
00059         getParentDocument()->removeTextBlock(m);
00060         m->forceRelease();
00061     }
00062     list.clear();
00063 
00064     // clear the decl block from parent text block list too
00065     if(m_declCodeBlock)
00066     {
00067         getParentDocument()->removeTextBlock(m_declCodeBlock);
00068         m_declCodeBlock->forceRelease();
00069         delete m_declCodeBlock;
00070     }
00071 
00072 }
00073 
00074 //
00075 // Methods
00076 //
00077 
00078 
00079 // Accessor methods
00080 //
00081 
00082 void CodeClassField::setParentUMLObject (UMLObject * obj) {
00083     UMLRole *role = dynamic_cast<UMLRole*>(obj);
00084     if(role) {
00085         UMLAssociation * parentAssoc = role->getParentAssociation();
00086         Uml::Association_Type atype = parentAssoc->getAssocType();
00087         m_parentIsAttribute = false;
00088 
00089         if ( atype == Uml::at_Association || atype == Uml::at_Association_Self)
00090             m_classFieldType = PlainAssociation; // Plain == Self + untyped associations
00091         else if (atype == Uml::at_Aggregation)
00092             m_classFieldType = Aggregation;
00093         else if (atype == Uml::at_Composition)
00094             m_classFieldType = Composition;
00095     } else {
00096         m_classFieldType = Attribute;
00097         m_parentIsAttribute = true;
00098     }
00099 }
00100 
00101 // Public attribute accessor methods
00102 //
00103 
00104 QString CodeClassField::getTypeName ( ) {
00105 
00106     if (parentIsAttribute())
00107     {
00108         UMLAttribute * at = (UMLAttribute*) getParentObject();
00109         return at->getTypeName();
00110     } else {
00111         UMLRole * role = (UMLRole*) getParentObject();
00112         if(fieldIsSingleValue()) {
00113             return getUMLObjectName(role->getObject());
00114         } else {
00115             return role->getName();
00116         }
00117     }
00118 }
00119 
00120 // get the type of object that will be added/removed from lists
00121 // of objects (as per specification of associations)
00122 QString CodeClassField::getListObjectType() {
00123     QString type = QString ("");
00124     if (!parentIsAttribute())
00125     {
00126         UMLRole * role = dynamic_cast<UMLRole*>(getParentObject());
00127         type = getUMLObjectName(role->getObject());
00128     }
00129     return type;
00130 }
00131 
00136 bool CodeClassField::parentIsAttribute ( ) {
00137     return m_parentIsAttribute;
00138     //  return (m_classFieldType == Attribute) ? true : false;
00139 }
00140 
00144 CodeClassField::ClassFieldType CodeClassField::getClassFieldType() {
00145     return m_classFieldType;
00146 }
00147 
00152 /*
00153 CodeClassFieldDialog * CodeClassField::getDialog ( ) {
00154     return m_dialog;
00155 }
00156 */
00157 
00158 // methods like this _shouldn't_ be needed IF we properly did things thruought the code.
00159 QString CodeClassField::getUMLObjectName(UMLObject *obj)
00160 {
00161     return (obj!=0)?obj->getName():QString("NULL");
00162 }
00163 
00167 bool CodeClassField::addMethod ( CodeAccessorMethod * add_object ) {
00168 
00169     CodeAccessorMethod::AccessorType type = add_object->getType();
00170 
00171     if(findMethodByType(type))
00172         return false;
00173     /*
00174         // this wont work as the key for QMap needs to inherit from QObject
00175         if(m_methodMap->contains(type))
00176                 return false; // return false, we already have some object with this tag in the list
00177         else
00178                 m_methodMap->insert(type, add_object);
00179     */
00180 
00181     m_methodVector.append(add_object);
00182     return true;
00183 }
00184 
00188 bool CodeClassField::removeMethod ( CodeAccessorMethod * remove_object ) {
00189     // m_methodMap->erase(remove_object->getType());
00190     m_methodVector.removeRef(remove_object);
00191     getParentDocument()->removeTextBlock(remove_object);
00192     return true;
00193 }
00194 
00200 CodeAccessorMethodList CodeClassField::getMethodList() {
00201     return m_methodVector;
00202 }
00203 
00208 bool CodeClassField::getWriteOutMethods ()
00209 {
00210     return m_writeOutMethods;
00211 }
00212 
00213 void CodeClassField::setWriteOutMethods ( bool val )
00214 {
00215     m_writeOutMethods = val;
00216     updateContent();
00217 }
00218 
00223 CodeClassFieldDeclarationBlock * CodeClassField::getDeclarationCodeBlock( )
00224 {
00225     return m_declCodeBlock;
00226 }
00227 
00228 // Other methods
00229 //
00230 
00234 void CodeClassField::loadFromXMI ( QDomElement & root ) {
00235     setAttributesFromNode(root);
00236 }
00237 
00241 void CodeClassField::setAttributesOnNode ( QDomDocument & doc, QDomElement & cfElem)
00242 {
00243 
00244     // super class
00245     CodeParameter::setAttributesOnNode(doc,cfElem);
00246 
00247     // now set local attributes/fields
00248     cfElem.setAttribute("field_type",m_classFieldType);
00249     cfElem.setAttribute("listClassName",m_listClassName);
00250     cfElem.setAttribute("writeOutMethods",getWriteOutMethods()?"true":"false");
00251 
00252     // record tag on declaration codeblock
00253     // which we will store in its own separate child node block
00254     m_declCodeBlock->saveToXMI(doc, cfElem);
00255 
00256     // now record the tags on our accessormethods
00257     CodeAccessorMethod *method;
00258     for (CodeAccessorMethodListIt it(m_methodVector); (method = it.current()) != NULL; ++it)
00259     {
00260         method->saveToXMI(doc,cfElem);
00261     }
00262 
00263 }
00264 
00268 void CodeClassField::setAttributesFromNode ( QDomElement & root) {
00269 
00270     // always disconnect
00271     getParentObject()->disconnect(this);
00272 
00273     // superclass call.. may reset the parent object
00274     CodeParameter::setAttributesFromNode(root);
00275 
00276     // make AFTER super-class call. This will reconnect to the parent
00277     // and re-check we have all needed child accessor methods and decl blocks
00278     initFields( );
00279 
00280     setWriteOutMethods(root.attribute("writeOutMethods","true") == "true" ? true : false);
00281     m_listClassName = root.attribute("listClassName","");
00282     m_classFieldType = (ClassFieldType) root.attribute("field_type","0").toInt();
00283 
00284     // load accessor methods now
00285     // by looking for our particular child element
00286     QDomNode node = root.firstChild();
00287     QDomElement element = node.toElement();
00288     while( !element.isNull() ) {
00289         QString tag = element.tagName();
00290         if( tag == "ccfdeclarationcodeblock" ) {
00291             m_declCodeBlock->loadFromXMI(element);
00292         } else
00293             if( tag == "codeaccessormethod" ) {
00294                 int type = element.attribute("accessType","0").toInt();
00295                 int role_id = element.attribute("role_id","-1").toInt();
00296                 CodeAccessorMethod * method = findMethodByType((CodeAccessorMethod::AccessorType) type, role_id);
00297                 if(method)
00298                     method->loadFromXMI(element);
00299                 else
00300                     kError()<<"Cant load code accessor method for type:"<<type<<" which doesn't exist in this codeclassfield. Is XMI out-dated or corrupt?"<<endl;
00301 
00302             } else
00303                 if( tag == "header" ) {
00304                     // this is treated in parent.. skip over here
00305                 } else
00306                     kWarning()<<"ERROR: bad savefile? code classfield loadFromXMI got child element with unknown tag:"<<tag<<" ignoring node."<<endl;
00307 
00308         node = element.nextSibling();
00309         element = node.toElement();
00310     }
00311 
00312 }
00313 
00317 void CodeClassField::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
00318     QDomElement docElement = doc.createElement( "codeclassfield" );
00319 
00320     setAttributesOnNode(doc, docElement);
00321 
00322     root.appendChild( docElement );
00323 }
00324 
00325 int CodeClassField::minimumListOccurances( ) {
00326     if (!parentIsAttribute())
00327     {
00328         UMLRole * role = dynamic_cast<UMLRole*>(getParentObject());
00329         QString multi = role->getMultiplicity();
00330         // ush. IF we had a multiplicty object, this would be much easier.
00331         if(!multi.isEmpty())
00332         {
00333             QString lowerBoundString = multi.remove(QRegExp("\\.\\.\\d+$"));
00334             if(!lowerBoundString.isEmpty() &&lowerBoundString.contains(QRegExp("^\\d+$")))
00335                 return lowerBoundString.toInt();
00336         }
00337 
00338     }
00339     return 0;
00340 }
00341 
00342 int CodeClassField::maximumListOccurances( ) {
00343     if (!parentIsAttribute())
00344     {
00345         UMLRole * role = dynamic_cast<UMLRole*>(getParentObject());
00346         QString multi = role->getMultiplicity();
00347         // ush. IF we had a multiplicty object, this would be much easier.
00348         if(!multi.isEmpty())
00349         {
00350             QString upperBoundString = multi.section(QRegExp("(\\.\\.)"),1);
00351             if(!upperBoundString.isEmpty() && upperBoundString.contains(QRegExp("^\\d+$")))
00352                 return upperBoundString.toInt();
00353             else
00354                 return -1; // unbounded
00355         } else
00356             return -1; // unbounded
00357 
00358     }
00359     return 1;
00360 }
00361 
00362 QString CodeClassField::cleanName ( const QString &name ) {
00363     return getParentDocument()->cleanName(name);
00364 }
00365 
00366 QString CodeClassField::fixInitialStringDeclValue(QString value, const QString &type)
00367 {
00368     // check for strings only
00369     if (!value.isEmpty() && type == "String") {
00370         if (!value.startsWith("\""))
00371             value.prepend("\"");
00372         if (!value.endsWith("\""))
00373             value.append("\"");
00374     }
00375     return value;
00376 }
00377 
00378 void CodeClassField::synchronize ()
00379 {
00380     updateContent();
00381     CodeAccessorMethod *method;
00382     for (CodeAccessorMethodListIt it(m_methodVector); (method = it.current()) != NULL; ++it)
00383         method->syncToParent();
00384 
00385     if(m_declCodeBlock)
00386         m_declCodeBlock->syncToParent();
00387 }
00388 
00389 CodeAccessorMethod * CodeClassField::findMethodByType ( CodeAccessorMethod::AccessorType type, int role_id)
00390 {
00391     //if we already know to which file this class was written/should be written, just return it.
00392     /*
00393         // argh. this wont work because "accessorType' doesn't inherit from QObject.
00394         if(m_methodMap->contains(type))
00395                 return ((*m_methodMap)[type]);
00396         CodeAccessorMethod * obj = NULL;
00397     */
00398     if(role_id > 1 || role_id < 0)
00399     {
00400         for (CodeAccessorMethod * m = m_methodVector.first(); m ; m= m_methodVector.next())
00401             if( m->getType() == type)
00402                 return m;
00403     } else {
00404         // ugh. forced into this underperforming algorithm because of bad association
00405         // design.
00406         for (CodeAccessorMethod * m = m_methodVector.first(); m ; m= m_methodVector.next())
00407         {
00408             UMLRole * role = dynamic_cast<UMLRole*>(m->getParentObject());
00409             if(!role)
00410                 kError()<<"    FindMethodByType()  cant create role for method type:"<<m->getType()<<endl;
00411             if( role && m->getType() == type && role->getRole() == role_id)
00412                 return m;
00413         }
00414 
00415     }
00416 
00417     return (CodeAccessorMethod *) NULL;
00418 }
00419 
00420 void CodeClassField::initAccessorMethods()
00421 {
00422 
00423     // everything gets potential get/set method
00424     //if(!m_methodMap->contains(CodeAccessorMethod::GET))
00425     if(!findMethodByType(CodeAccessorMethod::GET))
00426     {
00427         CodeAccessorMethod * method = CodeGenFactory::newCodeAccessorMethod (getParentDocument(), this, CodeAccessorMethod::GET);
00428         if(method)
00429         {
00430             method->setType(CodeAccessorMethod::GET);
00431             addMethod(method);
00432         }
00433     }
00434 
00435     if(!findMethodByType(CodeAccessorMethod::SET))
00436     {
00437         CodeAccessorMethod * method = CodeGenFactory::newCodeAccessorMethod (getParentDocument(), this, CodeAccessorMethod::SET);
00438         if(method) {
00439             method->setType(CodeAccessorMethod::SET);
00440             addMethod(method);
00441         }
00442     }
00443 
00444     // add in the add,remove and list methods for things which are role based.
00445     // (and only used if the role specifies a 'list' type object
00446     if (!parentIsAttribute()) {
00447 
00448         if(!findMethodByType(CodeAccessorMethod::ADD))
00449         {
00450             CodeAccessorMethod * method = CodeGenFactory::newCodeAccessorMethod (getParentDocument(), this, CodeAccessorMethod::ADD);
00451             if(method) {
00452                 method->setType(CodeAccessorMethod::ADD);
00453                 addMethod(method);
00454             }
00455         }
00456 
00457         if(!findMethodByType(CodeAccessorMethod::REMOVE))
00458         {
00459             CodeAccessorMethod * method = CodeGenFactory::newCodeAccessorMethod (getParentDocument(), this, CodeAccessorMethod::REMOVE);
00460             if(method) {
00461                 method->setType(CodeAccessorMethod::REMOVE);
00462                 addMethod(method);
00463             }
00464         }
00465 
00466         if(!findMethodByType(CodeAccessorMethod::LIST))
00467         {
00468             CodeAccessorMethod * method = CodeGenFactory::newCodeAccessorMethod (getParentDocument(), this, CodeAccessorMethod::LIST);
00469             if(method) {
00470                 method->setType(CodeAccessorMethod::LIST);
00471                 addMethod(method);
00472             }
00473         }
00474 
00475     }
00476 
00477 
00478 }
00479 
00480 void CodeClassField::updateContent()
00481 {
00482 
00483     // Set properties for writing out the various methods derived from UMLRoles.
00484     // I suppose this could be supported under individual accessor method synctoparent
00485     // calls, but its going to happen again and again for many languages. Why not a catch
00486     // all here? -b.t.
00487     if (parentIsAttribute())
00488     {
00489         for ( CodeAccessorMethod *method = m_methodVector.first(); method;
00490                 method = m_methodVector.next() )
00491             method->setWriteOutText( m_writeOutMethods );
00492         return;
00493     }
00494     UMLRole * role = dynamic_cast<UMLRole*>(getParentObject());
00495     Uml::Changeability_Type changeType = role->getChangeability();
00496     bool isSingleValue = fieldIsSingleValue();
00497     bool isEmptyRole = role->getName().isEmpty() ? true : false;
00498 
00499     for (CodeAccessorMethod * method = m_methodVector.first(); method; method=m_methodVector.next())
00500     {
00501 
00502         CodeAccessorMethod::AccessorType type = method->getType();
00503 
00504         // for role-based accessors, we DON'T write ourselves out when
00505         // the name of the role is not defined OR when the global flag
00506         // to not show ANY methods is set.
00507         if(!m_writeOutMethods || isEmptyRole)
00508         {
00509             method->setWriteOutText(false);
00510             continue;
00511         }
00512 
00513         // not to change if no tag (don't know what it is, OR its not an AutoGenerated method
00514         if(method->getContentType() != CodeBlock::AutoGenerated)
00515             continue;
00516 
00517         // first off, some accessor methods wont appear if its a singleValue
00518         // role and vice-versa
00519         if(isSingleValue)
00520         {
00521             switch(type) {
00522             case CodeAccessorMethod::SET:
00523                 // SET method true ONLY IF changeability is NOT Frozen
00524                 if (changeType != Uml::chg_Frozen)
00525                     method->setWriteOutText(true);
00526                 else
00527                     method->setWriteOutText(false);
00528                 break;
00529             case CodeAccessorMethod::GET:
00530                 method->setWriteOutText(true);
00531                 break;
00532             case CodeAccessorMethod::ADD:
00533             case CodeAccessorMethod::REMOVE:
00534             case CodeAccessorMethod::LIST:
00535             default: // list/add/remove always false
00536                 method->setWriteOutText(false);
00537                 break;
00538             }
00539         }
00540         else
00541         {
00542             switch(type) {
00543                 // get/set always false
00544             case CodeAccessorMethod::GET:
00545             case CodeAccessorMethod::SET:
00546                 method->setWriteOutText(false);
00547                 break;
00548             case CodeAccessorMethod::ADD:
00549                 // ADD method true ONLY IF changeability is NOT Frozen
00550                 if (changeType != Uml::chg_Frozen)
00551                     method->setWriteOutText(true);
00552                 else
00553                     method->setWriteOutText(false);
00554                 break;
00555             case CodeAccessorMethod::REMOVE:
00556                 // Remove methods ONLY IF changeability is Changeable
00557                 if (changeType == Uml::chg_Changeable)
00558                     method->setWriteOutText(true);
00559                 else
00560                     method->setWriteOutText(false);
00561                 break;
00562             case CodeAccessorMethod::LIST:
00563             default:
00564                 method->setWriteOutText(true);
00565                 break;
00566             }
00567         }
00568     }
00569 }
00570 
00571 // determine whether the parent object in this classfield indicates that it is
00572 // a single variable or a List (Vector). One day this will be done correctly with special
00573 // multiplicity object that we don't have to figure out what it means via regex.
00574 bool CodeClassField::fieldIsSingleValue ( )
00575 {
00576     // For the time being, all attributes ARE single values (yes,
00577     // I know this isnt always true, but we have to start somewhere.)
00578     if(parentIsAttribute())
00579         return true;
00580 
00581     UMLRole * role = dynamic_cast<UMLRole*>(getParentObject());
00582     if(!role)
00583         return true; // its really an attribute
00584 
00585     QString multi = role->getMultiplicity();
00586 
00587     if(multi.isEmpty() || multi.contains(QRegExp("^(0|1)$"))
00588             || multi.contains(QRegExp("^0\\.\\.1$")))
00589         return true;
00590 
00591     return false;
00592 }
00593 
00594 void CodeClassField::initFields(bool inConstructor) {
00595 
00596     m_writeOutMethods = false;
00597     m_listClassName = QString ("");
00598     m_declCodeBlock = NULL;
00599 
00600     m_methodVector.setAutoDelete(false);
00601     // m_methodMap = new QMap<CodeAccessorMethod::AccessorType, CodeAccessorMethod *>;
00602 
00603     if (!inConstructor)
00604         finishInitialization();
00605 }
00606 
00607 void CodeClassField::finishInitialization() {
00608     m_declCodeBlock = CodeGenFactory::newDeclarationCodeBlock(getParentDocument(), this);
00609     initAccessorMethods();
00610     updateContent();
00611 
00612     connect(getParentObject(),SIGNAL(modified()),this,SIGNAL(modified())); // child objects will trigger off this signal
00613 
00614 }
00615 
00616 #include "codeclassfield.moc"
KDE Logo
This file is part of the documentation for umbrello Version 3.1.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Jun 26 08:07:55 2007 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003