summaryrefslogtreecommitdiffstats
path: root/umbrello/umbrello/codeclassfield.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'umbrello/umbrello/codeclassfield.cpp')
-rw-r--r--umbrello/umbrello/codeclassfield.cpp617
1 files changed, 617 insertions, 0 deletions
diff --git a/umbrello/umbrello/codeclassfield.cpp b/umbrello/umbrello/codeclassfield.cpp
new file mode 100644
index 00000000..a19e664d
--- /dev/null
+++ b/umbrello/umbrello/codeclassfield.cpp
@@ -0,0 +1,617 @@
+/***************************************************************************
+ * *
+ * 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 <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Fri Jun 20 2003
+ */
+
+// own header
+#include "codeclassfield.h"
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+// 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<UMLRole*>(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
+//
+
+QString 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)
+QString CodeClassField::getListObjectType() {
+ QString type = QString ("");
+ if (!parentIsAttribute())
+ {
+ UMLRole * role = dynamic_cast<UMLRole*>(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.
+QString CodeClassField::getUMLObjectName(UMLObject *obj)
+{
+ return (obj!=0)?obj->getName():QString("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 QMap needs to inherit from QObject
+ 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 QPtrList<CodeMethodBlock *> 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 ( QDomElement & root ) {
+ setAttributesFromNode(root);
+}
+
+/** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+void CodeClassField::setAttributesOnNode ( QDomDocument & doc, QDomElement & 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 ( QDomElement & 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
+ QDomNode node = root.firstChild();
+ QDomElement element = node.toElement();
+ while( !element.isNull() ) {
+ QString 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:"<<type<<" which doesn't exist in this codeclassfield. Is XMI out-dated or corrupt?"<<endl;
+
+ } else
+ if( tag == "header" ) {
+ // this is treated in parent.. skip over here
+ } else
+ kWarning()<<"ERROR: bad savefile? code classfield loadFromXMI got child element with unknown tag:"<<tag<<" ignoring node."<<endl;
+
+ node = element.nextSibling();
+ element = node.toElement();
+ }
+
+}
+
+/**
+ * Save the XMI representation of this object
+ */
+void CodeClassField::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+ QDomElement docElement = doc.createElement( "codeclassfield" );
+
+ setAttributesOnNode(doc, docElement);
+
+ root.appendChild( docElement );
+}
+
+int CodeClassField::minimumListOccurances( ) {
+ if (!parentIsAttribute())
+ {
+ UMLRole * role = dynamic_cast<UMLRole*>(getParentObject());
+ QString multi = role->getMultiplicity();
+ // ush. IF we had a multiplicty object, this would be much easier.
+ if(!multi.isEmpty())
+ {
+ QString lowerBoundString = multi.remove(QRegExp("\\.\\.\\d+$"));
+ if(!lowerBoundString.isEmpty() &&lowerBoundString.contains(QRegExp("^\\d+$")))
+ return lowerBoundString.toInt();
+ }
+
+ }
+ return 0;
+}
+
+int CodeClassField::maximumListOccurances( ) {
+ if (!parentIsAttribute())
+ {
+ UMLRole * role = dynamic_cast<UMLRole*>(getParentObject());
+ QString multi = role->getMultiplicity();
+ // ush. IF we had a multiplicty object, this would be much easier.
+ if(!multi.isEmpty())
+ {
+ QString upperBoundString = multi.section(QRegExp("(\\.\\.)"),1);
+ if(!upperBoundString.isEmpty() && upperBoundString.contains(QRegExp("^\\d+$")))
+ return upperBoundString.toInt();
+ else
+ return -1; // unbounded
+ } else
+ return -1; // unbounded
+
+ }
+ return 1;
+}
+
+QString CodeClassField::cleanName ( const QString &name ) {
+ return getParentDocument()->cleanName(name);
+}
+
+QString CodeClassField::fixInitialStringDeclValue(const QString& val, const QString &type)
+{
+ QString value = val;
+ // check for strings only<F2>String 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 QObject.
+ 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<UMLRole*>(m->getParentObject());
+ if(!role)
+ kError()<<" FindMethodByType() cant create role for method type:"<<m->getType()<<endl;
+ if( role && m->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<UMLRole*>(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<UMLRole*>(getParentObject());
+ if(!role)
+ return true; // its really an attribute
+
+ QString multi = role->getMultiplicity();
+
+ if(multi.isEmpty() || multi.contains(QRegExp("^(0|1)$"))
+ || multi.contains(QRegExp("^0\\.\\.1$")))
+ return true;
+
+ return false;
+}
+
+void CodeClassField::initFields(bool inConstructor) {
+
+ m_writeOutMethods = false;
+ m_listClassName = QString ("");
+ m_declCodeBlock = NULL;
+
+ m_methodVector.setAutoDelete(false);
+ // m_methodMap = new QMap<CodeAccessorMethod::AccessorType, CodeAccessorMethod *>;
+
+ if (!inConstructor)
+ finishInitialization();
+}
+
+void CodeClassField::finishInitialization() {
+ m_declCodeBlock = CodeGenFactory::newDeclarationCodeBlock(getParentDocument(), this);
+ initAccessorMethods();
+ updateContent();
+
+ connect(getParentObject(),SIGNAL(modified()),this,SIGNAL(modified())); // child objects will trigger off this signal
+
+}
+
+#include "codeclassfield.moc"