umbrello API Documentation

attribute.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) 2002-2007                                               *
00009  *   Umbrello UML Modeller Authors <uml-devel@uml.sf.net>                  *
00010  ***************************************************************************/
00011 
00012 // own header
00013 #include "attribute.h"
00014 // qt/kde includes
00015 #include <qregexp.h>
00016 #include <kdebug.h>
00017 // app includes
00018 #include "classifier.h"
00019 #include "operation.h"
00020 #include "umlobject.h"
00021 #include "umldoc.h"
00022 #include "uml.h"
00023 #include "dialogs/umlattributedialog.h"
00024 #include "object_factory.h"
00025 
00026 UMLAttribute::UMLAttribute( const UMLObject *parent,
00027                             const QString& name, Uml::IDType id,
00028                             Uml::Visibility s,
00029                             UMLObject *type, const QString& iv )
00030         : UMLClassifierListItem(parent, name, id) {
00031     m_InitialValue = iv;
00032     m_BaseType = Uml::ot_Attribute;
00033     m_Vis = s;
00034     m_ParmKind = Uml::pd_In;
00035     /* CHECK: Do we need this:
00036     if (type == NULL) {
00037         type = Object_Factory::createUMLObject(Uml::ot_Datatype, "undef");
00038     }
00039      */
00040     m_pSecondary = type;
00041 }
00042 
00043 UMLAttribute::UMLAttribute(const UMLObject *parent) : UMLClassifierListItem(parent) {
00044     m_BaseType = Uml::ot_Attribute;
00045     m_Vis = Uml::Visibility::Private;
00046     m_ParmKind = Uml::pd_In;
00047 }
00048 
00049 UMLAttribute::~UMLAttribute() { }
00050 
00051 QString UMLAttribute::getInitialValue() {
00052     return m_InitialValue;
00053 }
00054 
00055 void UMLAttribute::setInitialValue(const QString &iv) {
00056     if(m_InitialValue != iv) {
00057         m_InitialValue = iv;
00058         UMLObject::emitModified();
00059     }
00060 }
00061 
00062 void UMLAttribute::setParmKind (Uml::Parameter_Direction pk) {
00063     m_ParmKind = pk;
00064 }
00065 
00066 Uml::Parameter_Direction UMLAttribute::getParmKind () const {
00067     return m_ParmKind;
00068 }
00069 
00070 QString UMLAttribute::toString(Uml::Signature_Type sig) {
00071     QString s;
00072 
00073     if(sig == Uml::st_ShowSig || sig == Uml::st_NoSig) {
00074         s = m_Vis.toString(true) + ' ';
00075     }
00076 
00077     if(sig == Uml::st_ShowSig || sig == Uml::st_SigNoVis) {
00078         // Determine whether the type name needs to be scoped.
00079         UMLObject *owningObject = static_cast<UMLObject*>(parent());
00080         if (owningObject->getBaseType() == Uml::ot_Operation) {
00081             // The immediate parent() is the UMLOperation but we want
00082             // the UMLClassifier:
00083             owningObject = static_cast<UMLObject*>(owningObject->parent());
00084         }
00085         UMLClassifier *ownParent = dynamic_cast<UMLClassifier*>(owningObject);
00086         if (ownParent == NULL) {
00087             kError() << "UMLAttribute::toString: parent "
00088             << owningObject->getName()
00089             << " is not a UMLClassifier" << endl;
00090             return "";
00091         }
00092         QString typeName;
00093         UMLClassifier *type = UMLClassifierListItem::getType();
00094         if (type) {
00095             UMLPackage *typeScope = type->getUMLPackage();
00096             if (typeScope != ownParent && typeScope != ownParent->getUMLPackage())
00097                 typeName = type->getFullyQualifiedName();
00098             else
00099                 typeName = type->getName();
00100         }
00101         // The default direction, "in", is not mentioned.
00102         // Perhaps we should include a pd_Unspecified in
00103         // Uml::Parameter_Direction to have better control over this.
00104         if (m_ParmKind == Uml::pd_InOut)
00105             s += "inout ";
00106         else if (m_ParmKind == Uml::pd_Out)
00107             s += "out ";
00108         // Construct the attribute text.
00109         QString string = s + getName() + " : " + typeName;
00110         if(m_InitialValue.length() > 0)
00111             string += " = " + m_InitialValue;
00112         return string;
00113     }
00114     return s + getName();
00115 }
00116 
00117 QString UMLAttribute::getFullyQualifiedName(QString separator,
00118                                             bool includeRoot /* = false */) const {
00119     UMLOperation *op = NULL;
00120     UMLObject *owningObject = static_cast<UMLObject*>(parent());
00121     if (owningObject->getBaseType() == Uml::ot_Operation) {
00122         op = static_cast<UMLOperation*>(owningObject);
00123         owningObject = static_cast<UMLObject*>(owningObject->parent());
00124     }
00125     UMLClassifier *ownParent = dynamic_cast<UMLClassifier*>(owningObject);
00126     if (ownParent == NULL) {
00127         kError() << "UMLAttribute::getFullyQualifiedName(" << m_Name
00128         << "): parent " << owningObject->getName()
00129         << " is not a UMLClassifier" << endl;
00130         return "";
00131     }
00132     if (separator.isEmpty())
00133         separator = UMLApp::app()->activeLanguageScopeSeparator();
00134     QString fqn = ownParent->getFullyQualifiedName(separator, includeRoot);
00135     if (op)
00136         fqn.append(separator + op->getName());
00137     fqn.append(separator + m_Name);
00138     return fqn;
00139 }
00140 
00141 bool UMLAttribute::operator==( UMLAttribute &rhs) {
00142     if( this == &rhs )
00143         return true;
00144 
00145     if( !UMLObject::operator==( rhs ) )
00146         return false;
00147 
00148     // The type name is the only distinguishing criterion.
00149     // (Some programming languages might support more, but others don't.)
00150     if (m_pSecondary != rhs.m_pSecondary)
00151         return false;
00152 
00153     return true;
00154 }
00155 
00156 void UMLAttribute::copyInto(UMLAttribute *rhs) const
00157 {
00158     // call the parent first.
00159     UMLClassifierListItem::copyInto(rhs);
00160 
00161     // Copy all datamembers
00162     rhs->m_pSecondary = m_pSecondary;
00163     rhs->m_SecondaryId = m_SecondaryId;
00164     rhs->m_InitialValue = m_InitialValue;
00165     rhs->m_ParmKind = m_ParmKind;
00166 }
00167 
00168 UMLObject* UMLAttribute::clone() const
00169 {
00170     //FIXME: The new attribute should be slaved to the NEW parent not the old.
00171     UMLAttribute *clone = new UMLAttribute( static_cast<UMLObject*>(parent()) );
00172     copyInto(clone);
00173 
00174     return clone;
00175 }
00176 
00177 
00178 void UMLAttribute::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
00179     QDomElement attributeElement = UMLObject::save("UML:Attribute", qDoc);
00180     if (m_pSecondary == NULL) {
00181         kDebug() << "UMLAttribute::saveToXMI(" << m_Name
00182         << "): m_pSecondary is NULL, m_SecondaryId is '"
00183         << m_SecondaryId << "'" << endl;
00184     } else {
00185         attributeElement.setAttribute( "type", ID2STR(m_pSecondary->getID()) );
00186     }
00187     if (! m_InitialValue.isEmpty())
00188         attributeElement.setAttribute( "initialValue", m_InitialValue );
00189     qElement.appendChild( attributeElement );
00190 }
00191 
00192 bool UMLAttribute::load( QDomElement & element ) {
00193     m_SecondaryId = element.attribute( "type", "" );
00194     // We use the m_SecondaryId as a temporary store for the xmi.id
00195     // of the attribute type model object.
00196     // It is resolved later on, when all classes have been loaded.
00197     // This deferred resolution is required because the xmi.id may
00198     // be a forward reference, i.e. it may identify a model object
00199     // that has not yet been loaded.
00200     if (m_SecondaryId.isEmpty()) {
00201         // Perhaps the type is stored in a child node:
00202         QDomNode node = element.firstChild();
00203         while (!node.isNull()) {
00204             if (node.isComment()) {
00205                 node = node.nextSibling();
00206                 continue;
00207             }
00208             QDomElement tempElement = node.toElement();
00209             QString tag = tempElement.tagName();
00210             if (!Uml::tagEq(tag, "type")) {
00211                 node = node.nextSibling();
00212                 continue;
00213             }
00214             m_SecondaryId = tempElement.attribute( "xmi.id", "" );
00215             if (m_SecondaryId.isEmpty())
00216                 m_SecondaryId = tempElement.attribute( "xmi.idref", "" );
00217             if (m_SecondaryId.isEmpty()) {
00218                 QDomNode inner = node.firstChild();
00219                 QDomElement tmpElem = inner.toElement();
00220                 m_SecondaryId = tmpElem.attribute( "xmi.id", "" );
00221                 if (m_SecondaryId.isEmpty())
00222                     m_SecondaryId = tmpElem.attribute( "xmi.idref", "" );
00223             }
00224             break;
00225         }
00226         if (m_SecondaryId.isEmpty()) {
00227             kDebug() << "UMLAttribute::load(" << m_Name << "): "
00228             << "cannot find type." << endl;
00229         }
00230     }
00231     m_InitialValue = element.attribute( "initialValue", "" );
00232     if (m_InitialValue.isEmpty()) {
00233         // for backward compatibility
00234         m_InitialValue = element.attribute( "value", "" );
00235     }
00236     return true;
00237 }
00238 
00239 bool UMLAttribute::showPropertiesDialog(QWidget* parent) {
00240     UMLAttributeDialog dialog(parent, this);
00241     return dialog.exec();
00242 }
00243 
00244 
00245 void UMLAttribute::setTemplateParams(QString templateParam, UMLClassifierList &templateParamList) {
00246     if (templateParam.isEmpty())
00247         return;
00248     QString type = templateParam.simplifyWhiteSpace();
00249 
00250     int start = type.find(QChar('<'));
00251     if (start >= 0 ) {
00252         int end = start;
00253         int count = 1;
00254         int len = type.length();
00255         while (count != 0 && ++end < len) {
00256             QChar c = type.at(end);
00257             if (c == QChar('<')) {
00258                 count++;
00259             }
00260             if (c == QChar('>')) {
00261                 count--;
00262             }
00263         }
00264         if (count != 0) {
00265             //The template is ill-formated, let's quit
00266             return;
00267         }
00268         setTemplateParams(type.mid(start + 1, end - start - 1), templateParamList);
00269         setTemplateParams(type.left(start) + type.right(len - end - 1), templateParamList);
00270     } else {
00271         QStringList paramsList = QStringList::split(QChar(','), type);
00272         for ( QStringList::Iterator it = paramsList.begin(); it != paramsList.end(); ++it ) {
00273             QString param = *it;
00274             if (!param.isEmpty()) {
00275                 UMLDoc *pDoc = UMLApp::app()->getDocument();
00276                 UMLObject* obj = pDoc->findUMLObject(param);
00277                 if (obj == NULL ) {
00278                     obj = pDoc->findUMLObject(param.remove(QChar(' ')));
00279                 }
00280                 if (obj != NULL ) {
00281                     //We want to list only the params that already exist in this document
00282                     //If the param doesnt't already exist, we couldn't draw an association anyway
00283                     UMLClassifier* tmpClassifier = static_cast<UMLClassifier*>(obj);
00284                     if (templateParamList.findRef(tmpClassifier) == -1) {
00285                         templateParamList.append(tmpClassifier);
00286                     }
00287                 }
00288             }
00289         }
00290     }
00291 }
00292 
00293 
00294 UMLClassifierList UMLAttribute::getTemplateParams() {
00295     UMLClassifierList templateParamList;
00296     QString type = getType()->getName();
00297     QString templateParam;
00298     // Handle C++/D/Java template/generic parameters
00299     const Uml::Programming_Language pl = UMLApp::app()->getActiveLanguage();
00300     if (pl == Uml::pl_Cpp || pl == Uml::pl_Java || pl == Uml::pl_D) {
00301         int start = type.find(QChar('<'));
00302         if (start >= 0 ) {
00303             int end = type.findRev(QChar('>'));
00304             if (end > start) {
00305                 templateParam = type.mid(start + 1, end - start - 1);
00306                 setTemplateParams(templateParam, templateParamList);
00307             }
00308         }
00309     }
00310     return templateParamList;
00311 }
00312 
00313 
00314 
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:54 2007 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003