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.
432 lines
15 KiB
432 lines
15 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) 2002-2007 *
|
|
* Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
|
|
***************************************************************************/
|
|
|
|
// own header
|
|
#include "operation.h"
|
|
|
|
// qt/kde includes
|
|
#include <tqregexp.h>
|
|
#include <kdebug.h>
|
|
#include <tdelocale.h>
|
|
|
|
// app includes
|
|
#include "attribute.h"
|
|
#include "classifier.h"
|
|
#include "uml.h"
|
|
#include "umldoc.h"
|
|
#include "uniqueid.h"
|
|
#include "dialogs/umloperationdialog.h"
|
|
|
|
UMLOperation::UMLOperation(const UMLClassifier *parent, const TQString& name,
|
|
Uml::IDType id, Uml::Visibility s, UMLObject *rt)
|
|
: UMLClassifierListItem(parent, name, id)
|
|
{
|
|
if (rt)
|
|
m_returnId = UniqueID::gen();
|
|
else
|
|
m_returnId = Uml::id_None;
|
|
m_pSecondary = rt;
|
|
m_Vis = s;
|
|
m_BaseType = Uml::ot_Operation;
|
|
m_bConst = false;
|
|
}
|
|
|
|
UMLOperation::UMLOperation(const UMLClassifier * parent)
|
|
: UMLClassifierListItem (parent)
|
|
{
|
|
m_BaseType = Uml::ot_Operation;
|
|
m_bConst = false;
|
|
}
|
|
|
|
UMLOperation::~UMLOperation() {
|
|
}
|
|
|
|
void UMLOperation::setType(UMLObject *type) {
|
|
UMLClassifierListItem::setType(type);
|
|
if (m_returnId == Uml::id_None)
|
|
m_returnId = UniqueID::gen();
|
|
}
|
|
|
|
void UMLOperation::moveParmLeft(UMLAttribute * a) {
|
|
if (a == NULL) {
|
|
kDebug() << "UMLOperation::moveParmLeft called on NULL attribute"
|
|
<< endl;
|
|
return;
|
|
}
|
|
kDebug() << "UMLOperation::moveParmLeft(" << a->getName() << ") called"
|
|
<< endl;
|
|
disconnect(a,TQT_SIGNAL(modified()),this,TQT_SIGNAL(modified()));
|
|
int idx;
|
|
if ( (idx=m_List.find( a )) == -1 ) {
|
|
kDebug() << "Error move parm left " << a->getName() << endl;
|
|
return;
|
|
}
|
|
if ( idx == 0 )
|
|
return;
|
|
m_List.remove( a );
|
|
m_List.insert( idx-1, a );
|
|
}
|
|
|
|
void UMLOperation::moveParmRight(UMLAttribute * a) {
|
|
if (a == NULL) {
|
|
kDebug() << "UMLOperation::moveParmRight called on NULL attribute"
|
|
<< endl;
|
|
return;
|
|
}
|
|
kDebug() << "UMLOperation::moveParmRight(" << a->getName() << ") called"
|
|
<< endl;
|
|
disconnect(a,TQT_SIGNAL(modified()),this,TQT_SIGNAL(modified()));
|
|
int idx;
|
|
if ( (idx=m_List.find( a )) == -1 ) {
|
|
kDebug() << "Error move parm right " << a->getName() << endl;
|
|
return;
|
|
}
|
|
int count = m_List.count();
|
|
if ( idx == count-1 )
|
|
return;
|
|
m_List.remove( a );
|
|
m_List.insert( idx+1, a );
|
|
}
|
|
|
|
void UMLOperation::removeParm(UMLAttribute * a, bool emitModifiedSignal /* =true */) {
|
|
if (a == NULL) {
|
|
kDebug() << "UMLOperation::removeParm called on NULL attribute"
|
|
<< endl;
|
|
return;
|
|
}
|
|
kDebug() << "UMLOperation::removeParm(" << a->getName() << ") called"
|
|
<< endl;
|
|
disconnect(a,TQT_SIGNAL(modified()),this,TQT_SIGNAL(modified()));
|
|
if(!m_List.remove(a))
|
|
kDebug() << "Error removing parm " << a->getName() << endl;
|
|
|
|
if (emitModifiedSignal)
|
|
emit modified();
|
|
}
|
|
|
|
UMLAttribute* UMLOperation::findParm(const TQString &name) {
|
|
UMLAttribute * obj=0;
|
|
for (obj = m_List.first(); obj; obj = m_List.next()) {
|
|
if (obj->getName() == name)
|
|
return obj;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
TQString UMLOperation::toString(Uml::Signature_Type sig) {
|
|
TQString s = "";
|
|
|
|
if(sig == Uml::st_ShowSig || sig == Uml::st_NoSig)
|
|
s = m_Vis.toString(true) + ' ';
|
|
|
|
s += getName();
|
|
Uml::Programming_Language pl = UMLApp::app()->getActiveLanguage();
|
|
bool parameterlessOpNeedsParentheses = (pl != Uml::pl_Pascal && pl != Uml::pl_Ada);
|
|
|
|
if (sig == Uml::st_NoSig || sig == Uml::st_NoSigNoVis) {
|
|
if (parameterlessOpNeedsParentheses)
|
|
s.append("()");
|
|
return s;
|
|
}
|
|
int last = m_List.count();
|
|
if (last) {
|
|
s.append("(");
|
|
int i = 0;
|
|
for (UMLAttribute *param = m_List.first(); param; param = m_List.next()) {
|
|
i++;
|
|
s.append(param->toString(Uml::st_SigNoVis));
|
|
if (i < last)
|
|
s.append(", ");
|
|
}
|
|
s.append(")");
|
|
} else if (parameterlessOpNeedsParentheses) {
|
|
s.append("()");
|
|
}
|
|
UMLClassifier *ownParent = static_cast<UMLClassifier*>(parent());
|
|
TQString returnType;
|
|
UMLClassifier *retType = UMLClassifierListItem::getType();
|
|
if (retType) {
|
|
UMLPackage *retVisibility = retType->getUMLPackage();
|
|
if (retVisibility != ownParent && retVisibility != ownParent->getUMLPackage())
|
|
returnType = retType->getFullyQualifiedName();
|
|
else
|
|
returnType = retType->getName();
|
|
}
|
|
if (returnType.length() > 0 && returnType != "void") {
|
|
s.append(" : ");
|
|
|
|
if (returnType.startsWith("virtual ")) {
|
|
s += returnType.mid(8);
|
|
} else {
|
|
s += returnType;
|
|
}
|
|
}
|
|
return s;
|
|
}
|
|
|
|
void UMLOperation::addParm(UMLAttribute *parameter, int position) {
|
|
if( position >= 0 && position <= (int)m_List.count() )
|
|
m_List.insert(position,parameter);
|
|
else
|
|
m_List.append( parameter );
|
|
UMLObject::emitModified();
|
|
connect(parameter,TQT_SIGNAL(modified()),this,TQT_SIGNAL(modified()));
|
|
}
|
|
|
|
TQString UMLOperation::getUniqueParameterName() {
|
|
TQString currentName = i18n("new_parameter");
|
|
TQString name = currentName;
|
|
for (int number = 1; findParm(name); number++) {
|
|
name = currentName + '_' + TQString::number(number);
|
|
}
|
|
return name;
|
|
}
|
|
|
|
bool UMLOperation::operator==( UMLOperation & rhs ) {
|
|
if( this == &rhs )
|
|
return true;
|
|
|
|
if( !UMLObject::operator==( rhs ) )
|
|
return false;
|
|
|
|
if( getTypeName() != rhs.getTypeName() )
|
|
return false;
|
|
|
|
if( m_List.count() != rhs.m_List.count() )
|
|
return false;
|
|
|
|
if(!(m_List == rhs.m_List))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void UMLOperation::copyInto(UMLOperation *rhs) const
|
|
{
|
|
UMLClassifierListItem::copyInto(rhs);
|
|
|
|
m_List.copyInto(&(rhs->m_List));
|
|
}
|
|
|
|
UMLObject* UMLOperation::clone() const
|
|
{
|
|
//FIXME: The new operation should be slaved to the NEW parent not the old.
|
|
UMLOperation *clone = new UMLOperation( static_cast<UMLClassifier*>(parent()) );
|
|
copyInto(clone);
|
|
|
|
return clone;
|
|
}
|
|
|
|
bool UMLOperation::resolveRef() {
|
|
bool overallSuccess = UMLObject::resolveRef();
|
|
// See remark on iteration style in UMLClassifier::resolveRef()
|
|
for (UMLAttributeListIt ait(m_List); ait.current(); ++ait) {
|
|
UMLAttribute *pAtt = ait.current();
|
|
if (! pAtt->resolveRef())
|
|
overallSuccess = false;
|
|
}
|
|
return overallSuccess;
|
|
}
|
|
|
|
bool UMLOperation::isConstructorOperation() {
|
|
// if an operation has the stereotype constructor
|
|
// return true
|
|
TQString strConstructor ("constructor");
|
|
if (getStereotype() == strConstructor)
|
|
return true;
|
|
|
|
UMLClassifier * c = static_cast<UMLClassifier*>(this->parent());
|
|
TQString cName = c->getName();
|
|
TQString opName = getName();
|
|
// It's a constructor operation if the operation name
|
|
// matches that of the parent classifier.
|
|
return (cName == opName);
|
|
}
|
|
|
|
bool UMLOperation::isDestructorOperation() {
|
|
if (getStereotype() == "destructor")
|
|
return true;
|
|
UMLClassifier * c = static_cast<UMLClassifier*>(this->parent());
|
|
|
|
TQString cName = c->getName();
|
|
TQString opName = getName();
|
|
// Special support for C++ syntax:
|
|
// It's a destructor operation if the operation name begins
|
|
// with "~" followed by the name of the parent classifier.
|
|
if (! opName.startsWith("~"))
|
|
return false;
|
|
opName.remove( TQRegExp("^~\\s*") );
|
|
return (cName == opName);
|
|
}
|
|
|
|
bool UMLOperation::isLifeOperation() {
|
|
return (isConstructorOperation() || isDestructorOperation());
|
|
}
|
|
|
|
void UMLOperation::setConst(bool b) {
|
|
m_bConst = b;
|
|
}
|
|
|
|
bool UMLOperation::getConst() const {
|
|
return m_bConst;
|
|
}
|
|
|
|
bool UMLOperation::showPropertiesDialog(TQWidget* parent) {
|
|
UMLOperationDialog dialog(parent, this);
|
|
return dialog.exec();
|
|
}
|
|
|
|
void UMLOperation::saveToXMI( TQDomDocument & qDoc, TQDomElement & qElement ) {
|
|
TQDomElement operationElement = UMLObject::save("UML:Operation", qDoc);
|
|
operationElement.setAttribute( "isQuery", m_bConst ? "true" : "false" );
|
|
TQDomElement featureElement = qDoc.createElement( "UML:BehavioralFeature.parameter" );
|
|
if (m_pSecondary) {
|
|
TQDomElement retElement = qDoc.createElement("UML:Parameter");
|
|
if (m_returnId == Uml::id_None) {
|
|
kDebug() << "UMLOperation::saveToXMI(" << m_Name
|
|
<< "): m_returnId is not set, setting it now." << endl;
|
|
m_returnId = UniqueID::gen();
|
|
}
|
|
retElement.setAttribute( "xmi.id", ID2STR(m_returnId) );
|
|
retElement.setAttribute( "type", ID2STR(m_pSecondary->getID()) );
|
|
retElement.setAttribute( "kind", "return" );
|
|
featureElement.appendChild( retElement );
|
|
} else {
|
|
kDebug() << "UMLOperation::saveToXMI: m_SecondaryId is "
|
|
<< m_SecondaryId << endl;
|
|
}
|
|
//save each attribute here, type different
|
|
UMLAttribute* pAtt = 0;
|
|
for( pAtt = m_List.first(); pAtt != 0; pAtt = m_List.next() ) {
|
|
TQDomElement attElement = pAtt->UMLObject::save("UML:Parameter", qDoc);
|
|
UMLClassifier *attrType = pAtt->getType();
|
|
if (attrType) {
|
|
attElement.setAttribute( "type", ID2STR(attrType->getID()) );
|
|
} else {
|
|
attElement.setAttribute( "type", pAtt -> getTypeName() );
|
|
}
|
|
attElement.setAttribute( "value", pAtt -> getInitialValue() );
|
|
|
|
Uml::Parameter_Direction kind = pAtt->getParmKind();
|
|
if (kind == Uml::pd_Out)
|
|
attElement.setAttribute("kind", "out");
|
|
else if (kind == Uml::pd_InOut)
|
|
attElement.setAttribute("kind", "inout");
|
|
// The default for the parameter kind is "in".
|
|
|
|
featureElement.appendChild( attElement );
|
|
}
|
|
if (featureElement.hasChildNodes())
|
|
operationElement.appendChild( featureElement );
|
|
qElement.appendChild( operationElement );
|
|
}
|
|
|
|
bool UMLOperation::load( TQDomElement & element ) {
|
|
m_SecondaryId = element.attribute( "type", "" );
|
|
TQString isQuery = element.attribute( "isQuery", "" );
|
|
if (!isQuery.isEmpty()) {
|
|
// We need this extra test for isEmpty() because load() might have been
|
|
// called again by the processing for BehavioralFeature.parameter (see below)
|
|
m_bConst = (isQuery == "true");
|
|
}
|
|
TQDomNode node = element.firstChild();
|
|
if (node.isComment())
|
|
node = node.nextSibling();
|
|
TQDomElement attElement = node.toElement();
|
|
while( !attElement.isNull() ) {
|
|
TQString tag = attElement.tagName();
|
|
if (Uml::tagEq(tag, "BehavioralFeature.parameter")) {
|
|
if (! load(attElement))
|
|
return false;
|
|
} else if (Uml::tagEq(tag, "Parameter")) {
|
|
TQString kind = attElement.attribute("kind", "");
|
|
if (kind.isEmpty()) {
|
|
// Perhaps the kind is stored in a child node:
|
|
for (TQDomNode n = attElement.firstChild(); !n.isNull(); n = n.nextSibling()) {
|
|
if (n.isComment())
|
|
continue;
|
|
TQDomElement tempElement = n.toElement();
|
|
TQString tag = tempElement.tagName();
|
|
if (!Uml::tagEq(tag, "kind"))
|
|
continue;
|
|
kind = tempElement.attribute( "xmi.value", "" );
|
|
break;
|
|
}
|
|
if (kind.isEmpty()) {
|
|
// kDebug() << "UMLOperation::load(" << m_Name << "): "
|
|
// << "cannot find kind, using default \"in\"." << endl;
|
|
kind = "in";
|
|
}
|
|
}
|
|
if (kind == "return") {
|
|
TQString returnId = attElement.attribute("xmi.id", "");
|
|
if (!returnId.isEmpty())
|
|
m_returnId = STR2ID(returnId);
|
|
m_SecondaryId = attElement.attribute( "type", "" );
|
|
if (m_SecondaryId.isEmpty()) {
|
|
// Perhaps the type is stored in a child node:
|
|
TQDomNode node = attElement.firstChild();
|
|
while (!node.isNull()) {
|
|
if (node.isComment()) {
|
|
node = node.nextSibling();
|
|
continue;
|
|
}
|
|
TQDomElement tempElement = node.toElement();
|
|
TQString tag = tempElement.tagName();
|
|
if (!Uml::tagEq(tag, "type")) {
|
|
node = node.nextSibling();
|
|
continue;
|
|
}
|
|
m_SecondaryId = tempElement.attribute( "xmi.id", "" );
|
|
if (m_SecondaryId.isEmpty())
|
|
m_SecondaryId = tempElement.attribute( "xmi.idref", "" );
|
|
if (m_SecondaryId.isEmpty()) {
|
|
TQDomNode inner = node.firstChild();
|
|
TQDomElement tmpElem = inner.toElement();
|
|
m_SecondaryId = tmpElem.attribute( "xmi.id", "" );
|
|
if (m_SecondaryId.isEmpty())
|
|
m_SecondaryId = tmpElem.attribute( "xmi.idref", "" );
|
|
}
|
|
break;
|
|
}
|
|
if (m_SecondaryId.isEmpty()) {
|
|
kError() << "UMLOperation::load(" << m_Name << "): "
|
|
<< "cannot find return type." << endl;
|
|
}
|
|
}
|
|
// Use deferred xmi.id resolution.
|
|
m_pSecondary = NULL;
|
|
} else {
|
|
UMLAttribute * pAtt = new UMLAttribute( this );
|
|
if( !pAtt->loadFromXMI(attElement) ) {
|
|
delete pAtt;
|
|
return false;
|
|
}
|
|
if (kind == "out")
|
|
pAtt->setParmKind(Uml::pd_Out);
|
|
else if (kind == "inout")
|
|
pAtt->setParmKind(Uml::pd_InOut);
|
|
else
|
|
pAtt->setParmKind(Uml::pd_In);
|
|
m_List.append( pAtt );
|
|
}
|
|
}
|
|
node = node.nextSibling();
|
|
if (node.isComment())
|
|
node = node.nextSibling();
|
|
attElement = node.toElement();
|
|
}//end while
|
|
return true;
|
|
}
|
|
|
|
|
|
#include "operation.moc"
|