/*************************************************************************** * * * 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-2006 * * Umbrello UML Modeller Authors * ***************************************************************************/ /* This code generated by: * Author : thomas * Date : Fri Jun 20 2003 */ // own header #include "codeclassfield.h" // qt/kde includes #include #include // app includes #include "association.h" #include "classifiercodedocument.h" #include "codegenerator.h" #include "attribute.h" #include "umlobject.h" #include "umlrole.h" #include "uml.h" #include "codegenerators/codegenfactory.h" // Constructors/Destructors // CodeClassField::CodeClassField ( ClassifierCodeDocument * doc , UMLRole * role) : CodeParameter ( doc , (UMLObject*) role) { setParentUMLObject(role); initFields(true); } CodeClassField::CodeClassField ( ClassifierCodeDocument * doc , UMLAttribute * attrib) : CodeParameter ( doc , (UMLObject*) attrib ) { setParentUMLObject(attrib); initFields(true); } CodeClassField::~CodeClassField ( ) { // remove methods from parent document CodeAccessorMethodList list = m_methodVector; for(CodeAccessorMethod * m = list.first(); m ; m=list.next()) { getParentDocument()->removeTextBlock(m); m->forceRelease(); } list.clear(); // clear the decl block from parent text block list too if(m_declCodeBlock) { getParentDocument()->removeTextBlock(m_declCodeBlock); m_declCodeBlock->forceRelease(); delete m_declCodeBlock; } } // // Methods // // Accessor methods // void CodeClassField::setParentUMLObject (UMLObject * obj) { UMLRole *role = dynamic_cast(obj); if(role) { UMLAssociation * parentAssoc = role->getParentAssociation(); Uml::Association_Type atype = parentAssoc->getAssocType(); m_parentIsAttribute = false; if ( atype == Uml::at_Association || atype == Uml::at_Association_Self) m_classFieldType = PlainAssociation; // Plain == Self + untyped associations else if (atype == Uml::at_Aggregation) m_classFieldType = Aggregation; else if (atype == Uml::at_Composition) m_classFieldType = Composition; } else { m_classFieldType = Attribute; m_parentIsAttribute = true; } } // Public attribute accessor methods // TQString CodeClassField::getTypeName ( ) { if (parentIsAttribute()) { UMLAttribute * at = (UMLAttribute*) getParentObject(); return at->getTypeName(); } else { UMLRole * role = (UMLRole*) getParentObject(); if(fieldIsSingleValue()) { return getUMLObjectName(role->getObject()); } else { return role->getName(); } } } // get the type of object that will be added/removed from lists // of objects (as per specification of associations) TQString CodeClassField::getListObjectType() { TQString type = TQString (""); if (!parentIsAttribute()) { UMLRole * role = dynamic_cast(getParentObject()); type = getUMLObjectName(role->getObject()); } return type; } /** * Get the value of m_isAbstract * @return the value of m_isAbstract */ bool CodeClassField::parentIsAttribute ( ) { return m_parentIsAttribute; // return (m_classFieldType == Attribute) ? true : false; } /** * Get the type of classfield this is. */ CodeClassField::ClassFieldType CodeClassField::getClassFieldType() { return m_classFieldType; } /** * Get the value of m_dialog * @return the value of m_dialog */ /* CodeClassFieldDialog * CodeClassField::getDialog ( ) { return m_dialog; } */ // methods like this _shouldn't_ be needed IF we properly did things thruought the code. TQString CodeClassField::getUMLObjectName(UMLObject *obj) { return (obj!=0)?obj->getName():TQString("NULL"); } /** * Add a Method object to the m_methodVector List */ bool CodeClassField::addMethod ( CodeAccessorMethod * add_object ) { CodeAccessorMethod::AccessorType type = add_object->getType(); if(findMethodByType(type)) return false; /* // this wont work as the key for TQMap needs to inherit from TQObject if(m_methodMap->contains(type)) return false; // return false, we already have some object with this tag in the list else m_methodMap->insert(type, add_object); */ m_methodVector.append(add_object); return true; } /** * Remove a Method object from m_methodVector List */ bool CodeClassField::removeMethod ( CodeAccessorMethod * remove_object ) { // m_methodMap->erase(remove_object->getType()); m_methodVector.removeRef(remove_object); getParentDocument()->removeTextBlock(remove_object); return true; } /** * Get the list of Method objects held by m_methodVector * @return TQPtrList list of Method objects held by * m_methodVector */ CodeAccessorMethodList CodeClassField::getMethodList() { return m_methodVector; } /** determine if we will *allow* methods to be viewable. * this flag is often used to toggle autogeneration of accessor * methods in the code class field. */ bool CodeClassField::getWriteOutMethods () { return m_writeOutMethods; } void CodeClassField::setWriteOutMethods ( bool val ) { m_writeOutMethods = val; updateContent(); } /** * return the declaration statement for this class field object. * will be empty until this (abstract) class is inherited in elsewhere. */ CodeClassFieldDeclarationBlock * CodeClassField::getDeclarationCodeBlock( ) { return m_declCodeBlock; } // Other methods // /** * load params from the appropriate XMI element node. */ void CodeClassField::loadFromXMI ( TQDomElement & root ) { setAttributesFromNode(root); } /** set attributes of the node that represents this class * in the XMI document. */ void CodeClassField::setAttributesOnNode ( TQDomDocument & doc, TQDomElement & cfElem) { // super class CodeParameter::setAttributesOnNode(doc,cfElem); // now set local attributes/fields cfElem.setAttribute("field_type",m_classFieldType); cfElem.setAttribute("listClassName",m_listClassName); cfElem.setAttribute("writeOutMethods",getWriteOutMethods()?"true":"false"); // record tag on declaration codeblock // which we will store in its own separate child node block m_declCodeBlock->saveToXMI(doc, cfElem); // now record the tags on our accessormethods CodeAccessorMethod *method; for (CodeAccessorMethodListIt it(m_methodVector); (method = it.current()) != NULL; ++it) { method->saveToXMI(doc,cfElem); } } /** set the class attributes of this object from * the passed element node. */ void CodeClassField::setAttributesFromNode ( TQDomElement & root) { // always disconnect getParentObject()->disconnect(this); // superclass call.. may reset the parent object CodeParameter::setAttributesFromNode(root); // make AFTER super-class call. This will reconnect to the parent // and re-check we have all needed child accessor methods and decl blocks initFields( ); setWriteOutMethods(root.attribute("writeOutMethods","true") == "true" ? true : false); m_listClassName = root.attribute("listClassName",""); m_classFieldType = (ClassFieldType) root.attribute("field_type","0").toInt(); // load accessor methods now // by looking for our particular child element TQDomNode node = root.firstChild(); TQDomElement element = node.toElement(); while( !element.isNull() ) { TQString tag = element.tagName(); if( tag == "ccfdeclarationcodeblock" ) { m_declCodeBlock->loadFromXMI(element); } else if( tag == "codeaccessormethod" ) { int type = element.attribute("accessType","0").toInt(); int role_id = element.attribute("role_id","-1").toInt(); CodeAccessorMethod * method = findMethodByType((CodeAccessorMethod::AccessorType) type, role_id); if(method) method->loadFromXMI(element); else kError()<<"Cant load code accessor method for type:"<(getParentObject()); TQString multi = role->getMultiplicity(); // ush. IF we had a multiplicty object, this would be much easier. if(!multi.isEmpty()) { TQString lowerBoundString = multi.remove(TQRegExp("\\.\\.\\d+$")); if(!lowerBoundString.isEmpty() &&lowerBoundString.contains(TQRegExp("^\\d+$"))) return lowerBoundString.toInt(); } } return 0; } int CodeClassField::maximumListOccurances( ) { if (!parentIsAttribute()) { UMLRole * role = dynamic_cast(getParentObject()); TQString multi = role->getMultiplicity(); // ush. IF we had a multiplicty object, this would be much easier. if(!multi.isEmpty()) { TQString upperBoundString = multi.section(TQRegExp("(\\.\\.)"),1); if(!upperBoundString.isEmpty() && upperBoundString.contains(TQRegExp("^\\d+$"))) return upperBoundString.toInt(); else return -1; // unbounded } else return -1; // unbounded } return 1; } TQString CodeClassField::cleanName ( const TQString &name ) { return getParentDocument()->cleanName(name); } TQString CodeClassField::fixInitialStringDeclValue(const TQString& val, const TQString &type) { TQString value = val; // check for strings onlyString value = val; if (!value.isEmpty() && type == "String") { if (!value.startsWith("\"")) value.prepend("\""); if (!value.endsWith("\"")) value.append("\""); } return value; } void CodeClassField::synchronize () { updateContent(); CodeAccessorMethod *method; for (CodeAccessorMethodListIt it(m_methodVector); (method = it.current()) != NULL; ++it) method->syncToParent(); if(m_declCodeBlock) m_declCodeBlock->syncToParent(); } CodeAccessorMethod * CodeClassField::findMethodByType ( CodeAccessorMethod::AccessorType type, int role_id) { //if we already know to which file this class was written/should be written, just return it. /* // argh. this wont work because "accessorType' doesn't inherit from TQObject. if(m_methodMap->contains(type)) return ((*m_methodMap)[type]); CodeAccessorMethod * obj = NULL; */ if(role_id > 1 || role_id < 0) { for (CodeAccessorMethod * m = m_methodVector.first(); m ; m= m_methodVector.next()) if( m->getType() == type) return m; } else { // ugh. forced into this underperforming algorithm because of bad association // design. for (CodeAccessorMethod * m = m_methodVector.first(); m ; m= m_methodVector.next()) { UMLRole * role = dynamic_cast(m->getParentObject()); if(!role) kError()<<" FindMethodByType() cant create role for method type:"<getType()<getType() == type && role->getRole() == role_id) return m; } } return (CodeAccessorMethod *) NULL; } void CodeClassField::initAccessorMethods() { // everything gets potential get/set method //if(!m_methodMap->contains(CodeAccessorMethod::GET)) if(!findMethodByType(CodeAccessorMethod::GET)) { CodeAccessorMethod * method = CodeGenFactory::newCodeAccessorMethod (getParentDocument(), this, CodeAccessorMethod::GET); if(method) { method->setType(CodeAccessorMethod::GET); addMethod(method); } } if(!findMethodByType(CodeAccessorMethod::SET)) { CodeAccessorMethod * method = CodeGenFactory::newCodeAccessorMethod (getParentDocument(), this, CodeAccessorMethod::SET); if(method) { method->setType(CodeAccessorMethod::SET); addMethod(method); } } // add in the add,remove and list methods for things which are role based. // (and only used if the role specifies a 'list' type object if (!parentIsAttribute()) { if(!findMethodByType(CodeAccessorMethod::ADD)) { CodeAccessorMethod * method = CodeGenFactory::newCodeAccessorMethod (getParentDocument(), this, CodeAccessorMethod::ADD); if(method) { method->setType(CodeAccessorMethod::ADD); addMethod(method); } } if(!findMethodByType(CodeAccessorMethod::REMOVE)) { CodeAccessorMethod * method = CodeGenFactory::newCodeAccessorMethod (getParentDocument(), this, CodeAccessorMethod::REMOVE); if(method) { method->setType(CodeAccessorMethod::REMOVE); addMethod(method); } } if(!findMethodByType(CodeAccessorMethod::LIST)) { CodeAccessorMethod * method = CodeGenFactory::newCodeAccessorMethod (getParentDocument(), this, CodeAccessorMethod::LIST); if(method) { method->setType(CodeAccessorMethod::LIST); addMethod(method); } } } } void CodeClassField::updateContent() { // Set properties for writing out the various methods derived from UMLRoles. // I suppose this could be supported under individual accessor method synctoparent // calls, but its going to happen again and again for many languages. Why not a catch // all here? -b.t. if (parentIsAttribute()) { for ( CodeAccessorMethod *method = m_methodVector.first(); method; method = m_methodVector.next() ) method->setWriteOutText( m_writeOutMethods ); return; } UMLRole * role = dynamic_cast(getParentObject()); Uml::Changeability_Type changeType = role->getChangeability(); bool isSingleValue = fieldIsSingleValue(); bool isEmptyRole = role->getName().isEmpty() ? true : false; for (CodeAccessorMethod * method = m_methodVector.first(); method; method=m_methodVector.next()) { CodeAccessorMethod::AccessorType type = method->getType(); // for role-based accessors, we DON'T write ourselves out when // the name of the role is not defined OR when the global flag // to not show ANY methods is set. if(!m_writeOutMethods || isEmptyRole) { method->setWriteOutText(false); continue; } // not to change if no tag (don't know what it is, OR its not an AutoGenerated method if(method->getContentType() != CodeBlock::AutoGenerated) continue; // first off, some accessor methods wont appear if its a singleValue // role and vice-versa if(isSingleValue) { switch(type) { case CodeAccessorMethod::SET: // SET method true ONLY IF changeability is NOT Frozen if (changeType != Uml::chg_Frozen) method->setWriteOutText(true); else method->setWriteOutText(false); break; case CodeAccessorMethod::GET: method->setWriteOutText(true); break; case CodeAccessorMethod::ADD: case CodeAccessorMethod::REMOVE: case CodeAccessorMethod::LIST: default: // list/add/remove always false method->setWriteOutText(false); break; } } else { switch(type) { // get/set always false case CodeAccessorMethod::GET: case CodeAccessorMethod::SET: method->setWriteOutText(false); break; case CodeAccessorMethod::ADD: // ADD method true ONLY IF changeability is NOT Frozen if (changeType != Uml::chg_Frozen) method->setWriteOutText(true); else method->setWriteOutText(false); break; case CodeAccessorMethod::REMOVE: // Remove methods ONLY IF changeability is Changeable if (changeType == Uml::chg_Changeable) method->setWriteOutText(true); else method->setWriteOutText(false); break; case CodeAccessorMethod::LIST: default: method->setWriteOutText(true); break; } } } } // determine whether the parent object in this classfield indicates that it is // a single variable or a List (Vector). One day this will be done correctly with special // multiplicity object that we don't have to figure out what it means via regex. bool CodeClassField::fieldIsSingleValue ( ) { // For the time being, all attributes ARE single values (yes, // I know this isnt always true, but we have to start somewhere.) if(parentIsAttribute()) return true; UMLRole * role = dynamic_cast(getParentObject()); if(!role) return true; // its really an attribute TQString multi = role->getMultiplicity(); if(multi.isEmpty() || multi.contains(TQRegExp("^(0|1)$")) || multi.contains(TQRegExp("^0\\.\\.1$"))) return true; return false; } void CodeClassField::initFields(bool inConstructor) { m_writeOutMethods = false; m_listClassName = TQString (""); m_declCodeBlock = NULL; m_methodVector.setAutoDelete(false); // m_methodMap = new TQMap; if (!inConstructor) finishInitialization(); } void CodeClassField::finishInitialization() { m_declCodeBlock = CodeGenFactory::newDeclarationCodeBlock(getParentDocument(), this); initAccessorMethods(); updateContent(); connect(getParentObject(),TQT_SIGNAL(modified()),this,TQT_SIGNAL(modified())); // child objects will trigger off this signal } #include "codeclassfield.moc"