umbrello API Documentation

umlrole.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) 2003-2007                                               *
00009  *   Umbrello UML Modeller Authors <uml-devel@uml.sf.net>                  *
00010  ***************************************************************************/
00011 
00012 // own header
00013 #include "umlrole.h"
00014 
00015 // qt/kde includes
00016 #include <kdebug.h>
00017 #include <qregexp.h>
00018 
00019 // local includes
00020 #include "association.h"
00021 #include "umldoc.h"
00022 #include "uml.h"
00023 
00024 
00025 // constructor
00026 UMLRole::UMLRole(UMLAssociation * parent, UMLObject * parentObj, Uml::Role_Type role)
00027         : UMLObject(const_cast<UMLAssociation*>(parent))
00028 {
00029     init(parent, parentObj, role);
00030 }
00031 
00032 UMLRole::~UMLRole() { }
00033 
00034 bool UMLRole::operator==(UMLRole &rhs) {
00035     if (this == &rhs) {
00036         return true;
00037     }
00038     return ( UMLObject::operator==( rhs ) &&
00039              m_Changeability == rhs.m_Changeability &&
00040              m_Multi == rhs.m_Multi &&
00041              m_Name == rhs.m_Name
00042            );
00043 }
00044 
00045 UMLAssociation * UMLRole::getParentAssociation () {
00046     return m_pAssoc;
00047 }
00048 
00049 UMLObject* UMLRole::getObject() {
00050     return m_pSecondary;
00051 }
00052 
00053 Uml::Changeability_Type UMLRole::getChangeability() const {
00054     return m_Changeability;
00055 }
00056 
00057 QString UMLRole::getMultiplicity() const {
00058     return m_Multi;
00059 }
00060 
00061 void UMLRole::setObject (UMLObject *obj) {
00062     // because we will get the id of this role from the parent
00063     // object, we CANT allow UMLRoles to take other UMLRoles as
00064     // parent objects. In fact, there is probably good reason
00065     // to only take UMLClassifiers here, but I'll leave it more open
00066     // for the time being. -b.t.
00067     if(obj && dynamic_cast<UMLRole*>(obj))
00068     {
00069         kError()<<"ERROR: UMLRole cant setObject() to another UMLRole!, ignoring"<<endl;
00070         return;
00071     }
00072 
00073     m_pSecondary = obj;
00074     UMLObject::emitModified();
00075 }
00076 
00077 void UMLRole::setChangeability (Uml::Changeability_Type value) {
00078     m_Changeability = value;
00079     UMLObject::emitModified();
00080 }
00081 
00082 void UMLRole::setMultiplicity ( const QString &multi ) {
00083     m_Multi = multi;
00084     UMLObject::emitModified();
00085 }
00086 
00087 Uml::Role_Type UMLRole::getRole() {
00088     return m_role;
00089 }
00090 
00091 void UMLRole::init(UMLAssociation * parent, UMLObject * parentObj, Uml::Role_Type r) {
00092     m_BaseType = Uml::ot_Role;
00093     m_role = r;
00094     m_pAssoc = parent;
00095     m_pSecondary = parentObj;
00096     m_Multi = "";
00097     m_Name = "";
00098     m_Changeability = Uml::chg_Changeable;
00099 
00100     // connect this up to parent
00101     connect(this,SIGNAL(modified()),parent,SIGNAL(modified()));
00102 }
00103 
00104 void UMLRole::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
00105     QDomElement roleElement = UMLObject::save("UML:AssociationEnd", qDoc);
00106     if (m_pSecondary)
00107         roleElement.setAttribute( "type", ID2STR(m_pSecondary->getID()) );
00108     else
00109         kError() << "UMLRole::saveToXMI(id " << ID2STR(m_nId)
00110         << "): m_pSecondary is NULL" << endl;
00111     if (!m_Multi.isEmpty())
00112         roleElement.setAttribute("multiplicity", m_Multi);
00113     if (m_role == Uml::A) {  // role aggregation based on parent type
00114         // role A
00115         switch (m_pAssoc->getAssocType()) {
00116         case Uml::at_Composition:
00117             roleElement.setAttribute("aggregation", "composite");
00118             break;
00119         case Uml::at_Aggregation:
00120             roleElement.setAttribute("aggregation", "aggregate");
00121             break;
00122         default:
00123             roleElement.setAttribute("aggregation", "none");
00124             break;
00125         }
00126         if (m_pAssoc->getAssocType() == Uml::at_UniAssociation) {
00127             // Normally the isNavigable attribute is "true".
00128             // We set it to false on role A to indicate that
00129             // role B gets an explicit arrowhead.
00130             roleElement.setAttribute("isNavigable", "false");
00131         } else {
00132             roleElement.setAttribute("isNavigable", "true");
00133         }
00134     } else {
00135         roleElement.setAttribute("aggregation", "none");
00136         roleElement.setAttribute("isNavigable", "true");
00137         //FIXME obviously this isn't standard XMI
00138         if (m_pAssoc->getAssocType() == Uml::at_Relationship) {
00139             roleElement.setAttribute("relationship", "true");
00140         }
00141     }
00142 
00143     roleElement.setAttribute("visibility", getVisibility().toString(false));
00144 
00145     switch (m_Changeability) {
00146     case Uml::chg_Frozen:
00147         roleElement.setAttribute("changeability", "frozen");
00148         break;
00149     case Uml::chg_AddOnly:
00150         roleElement.setAttribute("changeability", "addOnly");
00151         break;
00152     case Uml::chg_Changeable:
00153         roleElement.setAttribute("changeability", "changeable");
00154         break;
00155     }
00156     qElement.appendChild( roleElement );
00157 }
00158 
00159 bool UMLRole::load( QDomElement & element ) {
00160     UMLDoc * doc = UMLApp::app()->getDocument();
00161     QString type = element.attribute("type", "");
00162     if (!type.isEmpty()) {
00163         if (!m_SecondaryId.isEmpty())
00164             kWarning() << "UMLRole::load: overwriting old m_SecondaryId \""
00165             << m_SecondaryId << " with new value \""
00166             << type << "\"" << endl;
00167         m_SecondaryId = type;
00168     }
00169     // Inspect child nodes - for multiplicity (and type if not set above.)
00170     for (QDomNode node = element.firstChild(); !node.isNull(); node = node.nextSibling()) {
00171         if (node.isComment())
00172             continue;
00173         QDomElement tempElement = node.toElement();
00174         QString tag = tempElement.tagName();
00175         if (Uml::tagEq(tag, "name")) {
00176             m_Name = tempElement.text();
00177         } else if (Uml::tagEq(tag, "AssociationEnd.multiplicity")) {
00185             QDomNode n = tempElement.firstChild();
00186             if (node.isNull() || tempElement.isNull() || n.isNull() ||
00187                     n.toElement().isNull()) {
00188                 m_Multi = tempElement.text().stripWhiteSpace();
00189                 continue;
00190             }
00191             tempElement = n.toElement();
00192             tag = tempElement.tagName();
00193             if (!Uml::tagEq(tag, "Multiplicity")) {
00194                 m_Multi = tempElement.text().stripWhiteSpace();
00195                 continue;
00196             }
00197             n = tempElement.firstChild();
00198             tempElement = n.toElement();
00199             tag = tempElement.tagName();
00200             if (!Uml::tagEq(tag, "Multiplicity.range")) {
00201                 m_Multi = tempElement.text().stripWhiteSpace();
00202                 continue;
00203             }
00204             n = tempElement.firstChild();
00205             tempElement = n.toElement();
00206             tag = tempElement.tagName();
00207             if (!Uml::tagEq(tag, "MultiplicityRange")) {
00208                 m_Multi = tempElement.text().stripWhiteSpace();
00209                 continue;
00210             }
00211             QString multiUpper;
00212             if (tempElement.hasAttribute("lower")) {
00213                 m_Multi = tempElement.attribute("lower", "");
00214                 multiUpper = tempElement.attribute("upper", "");
00215                 if (!multiUpper.isEmpty()) {
00216                     if (!m_Multi.isEmpty())
00217                         m_Multi.append("..");
00218                     m_Multi.append(multiUpper);
00219                 }
00220                 continue;
00221             }
00222             n = tempElement.firstChild();
00223             while (!n.isNull()) {
00224                 tempElement = n.toElement();
00225                 tag = tempElement.tagName();
00226                 if (Uml::tagEq(tag, "MultiplicityRange.lower")) {
00227                     m_Multi = tempElement.text();
00228                 } else if (Uml::tagEq(tag, "MultiplicityRange.upper")) {
00229                     multiUpper = tempElement.text();
00230                 }
00231                 n = n.nextSibling();
00232             }
00233             if (!multiUpper.isEmpty()) {
00234                 if (!m_Multi.isEmpty())
00235                     m_Multi.append("..");
00236                 m_Multi.append(multiUpper);
00237             }
00238         } else if (m_SecondaryId.isEmpty() &&
00239                    (Uml::tagEq(tag, "type") ||
00240                     Uml::tagEq(tag, "participant"))) {
00241             m_SecondaryId = tempElement.attribute("xmi.id", "");
00242             if (m_SecondaryId.isEmpty())
00243                 m_SecondaryId = tempElement.attribute("xmi.idref", "");
00244             if (m_SecondaryId.isEmpty()) {
00245                 QDomNode inner = tempElement.firstChild();
00246                 QDomElement innerElem = inner.toElement();
00247                 m_SecondaryId = innerElem.attribute("xmi.id", "");
00248                 if (m_SecondaryId.isEmpty())
00249                     m_SecondaryId = innerElem.attribute("xmi.idref", "");
00250             }
00251         }
00252     }
00253     if (!m_Multi.isEmpty())
00254         kDebug() << "UMLRole::load(" << m_Name << "): m_Multi is " << m_Multi << endl;
00255     if (m_SecondaryId.isEmpty()) {
00256         kError() << "UMLRole::load: type not given or illegal" << endl;
00257         return false;
00258     }
00259     UMLObject * obj;
00260     obj = doc->findObjectById(STR2ID(m_SecondaryId));
00261     if (obj) {
00262         m_pSecondary = obj;
00263         m_SecondaryId = "";
00264     }
00265 
00266     // block signals to prevent needless updating
00267     blockSignals(true);
00268     // Here comes the handling of the association type.
00269     // This is open for discussion - I'm pretty sure there are better ways..
00270 
00271     // Yeah, for one, setting the *parent* object parameters from here is sucky
00272     // as hell. Why are we using roleA to store what is essentially a parent (association)
00273     // parameter, eh? The UML13.dtd is pretty silly, but since that is what
00274     // is driving us to that point, we have to go with it. Some analysis of
00275     // the component roles/linked items needs to be done in order to get things
00276     // right. *sigh* -b.t.
00277 
00278     // Setting association type from the role (A)
00279     // Determination of the "aggregation" attribute used to be done only
00280     // when (m_role == Uml::A) but some XMI writers (e.g. StarUML) place
00281     // the aggregation attribute at role B.
00282     // The role end with the aggregation unequal to "none" wins.
00283     QString aggregation = element.attribute("aggregation", "none");
00284     if (aggregation == "composite")
00285         m_pAssoc->setAssocType(Uml::at_Composition);
00286     else if (aggregation == "shared"       // UML1.3
00287           || aggregation == "aggregate")   // UML1.4
00288         m_pAssoc->setAssocType(Uml::at_Aggregation);
00289 
00290     if (!element.hasAttribute("isNavigable")) {
00291         /* Backward compatibility mode: In Umbrello version 1.3.x the
00292            logic for saving the isNavigable flag was wrong.
00293            May happen on loading role A.
00294          */
00295         m_pAssoc->setOldLoadMode(true);
00296     } else if (m_pAssoc->getOldLoadMode() == true) {
00297         /* Here is the original logic:
00298            " Role B:
00299              If isNavigable is not given, we make no change to the
00300              association type.
00301              If isNavigable is given, and is "true", then we assume that
00302              the association's other end (role A) is not navigable, and
00303              therefore we change the association type to UniAssociation.
00304              The case that isNavigable is given as "false" is ignored.
00305              Combined with the association type logic for role A, this
00306              allows us to support at_Association and at_UniAssociation. "
00307          */
00308         if (element.attribute("isNavigable") == "true")
00309             m_pAssoc->setAssocType(Uml::at_UniAssociation);
00310     } else if (element.attribute("isNavigable") == "false") {
00311         m_pAssoc->setAssocType(Uml::at_UniAssociation);
00312     }
00313 
00314     //FIXME not standard XMI
00315     if (element.hasAttribute("relationship")) {
00316         if (element.attribute("relationship") == "true") {
00317             m_pAssoc->setAssocType(Uml::at_Relationship);
00318         }
00319     }
00320 
00321     if (m_Multi.isEmpty())
00322         m_Multi = element.attribute("multiplicity", "");
00323 
00324     // Changeability defaults to Changeable if it cant set it here..
00325     m_Changeability = Uml::chg_Changeable;
00326     QString changeability = element.attribute("changeability", "");
00327     if (changeability.isEmpty())
00328         element.attribute("changeable", "");  // for backward compatibility
00329     if (changeability == "frozen")
00330         m_Changeability = Uml::chg_Frozen;
00331     else if (changeability == "addOnly")
00332         m_Changeability = Uml::chg_AddOnly;
00333 
00334     // finished config, now unblock
00335     blockSignals(false);
00336     return true;
00337 }
00338 
00339 #include "umlrole.moc"
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:08:01 2007 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003