You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
618 lines
19 KiB
618 lines
19 KiB
/***************************************************************************
|
|
* *
|
|
* 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 <tqregexp.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 tqparent 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 tqparent 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
|
|
//
|
|
|
|
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<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.
|
|
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->tqcontains(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<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 ( 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 tqparent object
|
|
CodeParameter::setAttributesFromNode(root);
|
|
|
|
// make AFTER super-class call. This will reconnect to the tqparent
|
|
// 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:"<<type<<" which doesn't exist in this codeclassfield. Is XMI out-dated or corrupt?"<<endl;
|
|
|
|
} else
|
|
if( tag == "header" ) {
|
|
// this is treated in tqparent.. 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 ( TQDomDocument & doc, TQDomElement & root ) {
|
|
TQDomElement docElement = doc.createElement( "codeclassfield" );
|
|
|
|
setAttributesOnNode(doc, docElement);
|
|
|
|
root.appendChild( docElement );
|
|
}
|
|
|
|
int CodeClassField::minimumListOccurances( ) {
|
|
if (!parentIsAttribute())
|
|
{
|
|
UMLRole * role = dynamic_cast<UMLRole*>(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.tqcontains(TQRegExp("^\\d+$")))
|
|
return lowerBoundString.toInt();
|
|
}
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int CodeClassField::maximumListOccurances( ) {
|
|
if (!parentIsAttribute())
|
|
{
|
|
UMLRole * role = dynamic_cast<UMLRole*>(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.tqcontains(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 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 TQObject.
|
|
if(m_methodMap->tqcontains(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->tqcontains(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 synctotqparent
|
|
// 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 tqparent 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
|
|
|
|
TQString multi = role->getMultiplicity();
|
|
|
|
if(multi.isEmpty() || multi.tqcontains(TQRegExp("^(0|1)$"))
|
|
|| multi.tqcontains(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<CodeAccessorMethod::AccessorType, CodeAccessorMethod *>;
|
|
|
|
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"
|