00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "association.h"
00014
00015 #include <kdebug.h>
00016 #include <klocale.h>
00017 #include <qregexp.h>
00018
00019 #include "classifier.h"
00020 #include "folder.h"
00021 #include "uml.h"
00022 #include "umldoc.h"
00023 #include "umlrole.h"
00024 #include "uniqueid.h"
00025 #include "model_utils.h"
00026
00027 using namespace Uml;
00028
00029
00030 const Uml::Association_Type UMLAssociation::atypeFirst = Uml::at_Generalization;
00031 const Uml::Association_Type UMLAssociation::atypeLast = Uml::at_Relationship;
00032 const unsigned UMLAssociation::nAssocTypes = (unsigned)atypeLast -
00033 (unsigned)atypeFirst + 1;
00034
00035
00036 UMLAssociation::UMLAssociation( Association_Type type,
00037 UMLObject * roleA, UMLObject * roleB )
00038 : UMLObject("")
00039 {
00040 init(type, roleA, roleB);
00041
00042 m_pRole[Uml::A]->setID( UniqueID::gen() );
00043 m_pRole[Uml::B]->setID( UniqueID::gen() );
00044 }
00045
00046 UMLAssociation::UMLAssociation( Association_Type type )
00047 : UMLObject("", Uml::id_Reserved)
00048 {
00049 init(type, NULL, NULL);
00050 }
00051
00052
00053 UMLAssociation::~UMLAssociation( ) {
00054 if (m_pRole[A] == NULL) {
00055 kError() << "UMLAssociation destructor: m_pRole[A] is NULL already"
00056 << endl;
00057 } else {
00058 delete m_pRole[A];
00059 m_pRole[A] = NULL;
00060 }
00061 if (m_pRole[B] == NULL) {
00062 kError() << "UMLAssociation destructor: m_pRole[B] is NULL already"
00063 << endl;
00064 } else {
00065 delete m_pRole[B];
00066 m_pRole[B] = NULL;
00067 }
00068 }
00069
00070 bool UMLAssociation::operator==(UMLAssociation &rhs) {
00071 if (this == &rhs) {
00072 return true;
00073 }
00074 return ( UMLObject::operator== ( rhs ) &&
00075 m_AssocType == rhs.m_AssocType &&
00076 m_Name == rhs.m_Name &&
00077 m_pRole[A] == rhs.m_pRole[A] &&
00078 m_pRole[B] == rhs.m_pRole[B] );
00079 }
00080
00081 const QString UMLAssociation::assocTypeStr[UMLAssociation::nAssocTypes] = {
00082
00083
00084 i18n("Generalization"),
00085 i18n("Aggregation"),
00086 i18n("Dependency"),
00087 i18n("Association"),
00088 i18n("Self Association"),
00089 i18n("Collaboration Message"),
00090 i18n("Sequence Message"),
00091 i18n("Collaboration Self Message"),
00092 i18n("Sequence Self Message"),
00093 i18n("Containment"),
00094 i18n("Composition"),
00095 i18n("Realization"),
00096 i18n("Uni Association"),
00097 i18n("Anchor"),
00098 i18n("State Transition"),
00099 i18n("Activity"),
00100 };
00101
00102 Uml::Association_Type UMLAssociation::getAssocType() const {
00103 return m_AssocType;
00104 }
00105
00106 QString UMLAssociation::toString ( ) const
00107 {
00108 QString string;
00109 if(m_pRole[A])
00110 {
00111 string += m_pRole[A]->getObject()->getName();
00112 string += ':';
00113 string += m_pRole[A]->getName();
00114 }
00115 string += ':' + typeAsString(m_AssocType) + ':';
00116 if(m_pRole[B])
00117 {
00118 string += m_pRole[B]->getObject( )->getName();
00119 string += ':';
00120 string += m_pRole[B]->getName();
00121 }
00122 return string;
00123 }
00124
00125 QString UMLAssociation::typeAsString (Uml::Association_Type atype)
00126 {
00127 if (atype < atypeFirst || atype > atypeLast)
00128 return "";
00129 return assocTypeStr[(unsigned)atype - (unsigned)atypeFirst];
00130 }
00131
00132 bool UMLAssociation::assocTypeHasUMLRepresentation(Uml::Association_Type atype)
00133 {
00134 return (atype == Uml::at_Generalization ||
00135 atype == Uml::at_Realization ||
00136 atype == Uml::at_Association ||
00137 atype == Uml::at_Association_Self ||
00138 atype == Uml::at_UniAssociation ||
00139 atype == Uml::at_Aggregation ||
00140 atype == Uml::at_Relationship ||
00141 atype == Uml::at_Composition ||
00142 atype == Uml::at_Dependency);
00143 }
00144
00145 bool UMLAssociation::resolveRef() {
00146 bool successA = getUMLRole(A)->resolveRef();
00147 bool successB = getUMLRole(B)->resolveRef();
00148 if (successA && successB) {
00149 UMLObject *objA = getUMLRole(A)->getObject();
00150 UMLObject *objB = getUMLRole(B)->getObject();
00151
00152 if (m_AssocType == Uml::at_Generalization &&
00153 (objA && objA->getBaseType() == Uml::ot_Interface ||
00154 objB && objB->getBaseType() == Uml::ot_Interface))
00155 m_AssocType = Uml::at_Realization;
00156 m_pUMLPackage->addAssocToConcepts(this);
00157 return true;
00158 }
00159 return false;
00160 }
00161
00162 void UMLAssociation::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
00163 if (m_AssocType == Uml::at_Generalization) {
00164 QDomElement assocElement = UMLObject::save("UML:Generalization", qDoc);
00165 assocElement.setAttribute( "discriminator", "" );
00166 assocElement.setAttribute( "child", ID2STR(getObjectId(A)) );
00167 assocElement.setAttribute( "parent", ID2STR(getObjectId(B)) );
00168 qElement.appendChild( assocElement );
00169 return;
00170 }
00171 if (m_AssocType == Uml::at_Realization) {
00172 QDomElement assocElement = UMLObject::save("UML:Abstraction", qDoc);
00173 assocElement.setAttribute( "client", ID2STR(getObjectId(A)) );
00174 assocElement.setAttribute( "supplier", ID2STR(getObjectId(B)) );
00175 qElement.appendChild( assocElement );
00176 return;
00177 }
00178 if (m_AssocType == Uml::at_Dependency) {
00179 QDomElement assocElement = UMLObject::save("UML:Dependency", qDoc);
00180 assocElement.setAttribute( "client", ID2STR(getObjectId(A)) );
00181 assocElement.setAttribute( "supplier", ID2STR(getObjectId(B)) );
00182 qElement.appendChild( assocElement );
00183 return;
00184 }
00185 QDomElement associationElement = UMLObject::save("UML:Association", qDoc);
00186 QDomElement connElement = qDoc.createElement("UML:Association.connection");
00187 getUMLRole(A)->saveToXMI (qDoc, connElement);
00188 getUMLRole(B)->saveToXMI (qDoc, connElement);
00189 associationElement.appendChild (connElement);
00190 qElement.appendChild( associationElement );
00191 }
00192
00193 bool UMLAssociation::load( QDomElement & element ) {
00194 if (getID() == Uml::id_None)
00195 return false;
00196
00197 UMLDoc * doc = UMLApp::app()->getDocument();
00198 UMLObject * obj[2] = { NULL, NULL };
00199 if (m_AssocType == Uml::at_Generalization ||
00200 m_AssocType == Uml::at_Realization ||
00201 m_AssocType == Uml::at_Dependency) {
00202 for (unsigned r = Uml::A; r <= Uml::B; r++) {
00203 const QString fetch = (m_AssocType == Uml::at_Generalization ?
00204 r == Uml::A ? "child" : "parent"
00205 : r == Uml::A ? "client" : "supplier");
00206 QString roleIdStr = element.attribute(fetch, "");
00207 if (roleIdStr.isEmpty()) {
00208
00209 continue;
00210 }
00211
00212
00213 obj[r] = doc->findObjectById(STR2ID(roleIdStr));
00214 Uml::Role_Type role = (Uml::Role_Type)r;
00215 if (obj[r] == NULL) {
00216 m_pRole[role]->setSecondaryId(roleIdStr);
00217 } else {
00218 m_pRole[role]->setObject(obj[r]);
00219 if (m_pUMLPackage == NULL) {
00220 Uml::Model_Type mt = Model_Utils::convert_OT_MT(obj[r]->getBaseType());
00221 m_pUMLPackage = doc->getRootFolder(mt);
00222 kDebug() << "UMLAssociation::load(assoctype " << m_AssocType
00223 << "): setting model type " << mt << endl;
00224 }
00225 }
00226 }
00227 if (obj[A] == NULL || obj[B] == NULL) {
00228 for (QDomNode node = element.firstChild(); !node.isNull();
00229 node = node.nextSibling()) {
00230 if (node.isComment())
00231 continue;
00232 QDomElement tempElement = node.toElement();
00233 QString tag = tempElement.tagName();
00234 if (Model_Utils::isCommonXMIAttribute(tag))
00235 continue;
00236
00237
00238
00239 QString idStr = tempElement.attribute( "xmi.id", "" );
00240 if (idStr.isEmpty())
00241 idStr = tempElement.attribute( "xmi.idref", "" );
00242 if (idStr.isEmpty()) {
00243 QDomNode inner = node.firstChild();
00244 QDomElement tmpElem = inner.toElement();
00245 idStr = tmpElem.attribute( "xmi.id", "" );
00246 if (idStr.isEmpty())
00247 idStr = tmpElem.attribute( "xmi.idref", "" );
00248 }
00249 if (idStr.isEmpty()) {
00250 kError() << "UMLAssociation::load (type " << m_AssocType
00251 << ", id " << ID2STR(getID()) << "): "
00252 << "xmi id not given for " << tag << endl;
00253 continue;
00254 }
00255
00256
00257 if (tagEq(tag, "child") || tagEq(tag, "subtype") || tagEq(tag, "client")) {
00258 getUMLRole(A)->setSecondaryId(idStr);
00259 } else {
00260 getUMLRole(B)->setSecondaryId(idStr);
00261 }
00262 }
00263 }
00264
00265
00266 if (m_AssocType == Uml::at_Generalization &&
00267 (obj[A] && obj[A]->getBaseType() == Uml::ot_Interface ||
00268 obj[B] && obj[B]->getBaseType() == Uml::ot_Interface))
00269 m_AssocType = Uml::at_Realization;
00270
00271 return true;
00272 }
00273
00274 for (QDomNode node = element.firstChild(); !node.isNull();
00275 node = node.nextSibling()) {
00276
00277 if (node.isComment())
00278 continue;
00279 QDomElement tempElement = node.toElement();
00280 QString tag = tempElement.tagName();
00281 if (Model_Utils::isCommonXMIAttribute(tag))
00282 continue;
00283 if (!tagEq(tag, "Association.connection") &&
00284 !tagEq(tag, "Namespace.ownedElement") &&
00285 !tagEq(tag, "Namespace.contents")) {
00286 kWarning() << "UMLAssociation::load: "
00287 << "unknown child node " << tag << endl;
00288 continue;
00289 }
00290
00291 node = tempElement.firstChild();
00292 while (node.isComment())
00293 node = node.nextSibling();
00294 tempElement = node.toElement();
00295 if (tempElement.isNull()) {
00296 kWarning() << "UML:Association : element (A) is Null" << endl;
00297 return false;
00298 }
00299 tag = tempElement.tagName();
00300 if (!tagEq(tag, "AssociationEndRole") &&
00301 !tagEq(tag, "AssociationEnd")) {
00302 kWarning() << "UMLAssociation::load: "
00303 << "unknown child (A) tag " << tag << endl;
00304 return false;
00305 }
00306 if (! getUMLRole(A)->loadFromXMI(tempElement))
00307 return false;
00308
00309 node = node.nextSibling();
00310 while (node.isComment())
00311 node = node.nextSibling();
00312 tempElement = node.toElement();
00313 if (tempElement.isNull()) {
00314 kWarning() << "UML:Association : element (B) is Null" << endl;
00315 return false;
00316 }
00317 tag = tempElement.tagName();
00318 if (!tagEq(tag, "AssociationEndRole") &&
00319 !tagEq(tag, "AssociationEnd")) {
00320 kWarning() << "UMLAssociation::load: "
00321 << "unknown child (B) tag " << tag << endl;
00322 return false;
00323 }
00324 if (! getUMLRole(B)->loadFromXMI(tempElement))
00325 return false;
00326
00327 if (m_pUMLPackage == NULL) {
00328 Uml::Model_Type mt = Model_Utils::convert_OT_MT(getObject(B)->getBaseType());
00329 m_pUMLPackage = doc->getRootFolder(mt);
00330 kDebug() << "UMLAssociation::load: setting model type " << mt << endl;
00331 }
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343 if (m_AssocType == Uml::at_Association && getObjectId(A) == getObjectId(B))
00344 m_AssocType = Uml::at_Association_Self;
00345
00346
00347 if (m_AssocType == Uml::at_Unknown) {
00348 m_AssocType = Uml::at_Association;
00349 }
00350
00351 return true;
00352 }
00353
00354
00355 QString assocTypeStr = element.attribute( "assoctype", "-1" );
00356 Uml::Association_Type assocType = Uml::at_Unknown;
00357 if (assocTypeStr[0] >= 'a' && assocTypeStr[0] <= 'z') {
00358
00359 const QString assocTypeString[nAssocTypes] = {
00360 "generalization",
00361 "aggregation",
00362 "dependency",
00363 "association",
00364 "associationself",
00365 "collmessage",
00366 "seqmessage",
00367 "collmessageself",
00368 "seqmessageself",
00369 "implementation",
00370 "composition",
00371 "realization",
00372 "uniassociation",
00373 "anchor",
00374 "state",
00375 "activity",
00376 "relationship"
00377 };
00378
00379 unsigned index;
00380 for (index = 0; index < nAssocTypes; index++)
00381 if (assocTypeStr == assocTypeString[index])
00382 break;
00383 if (index < nAssocTypes)
00384 assocType = (Uml::Association_Type)index;
00385 } else {
00386 int assocTypeNum = assocTypeStr.toInt();
00387 if (assocTypeNum < (int)atypeFirst || assocTypeNum > (int)atypeLast) {
00388 kWarning() << "bad assoctype of UML:Association "
00389 << ID2STR(getID()) << endl;
00390 return false;
00391 }
00392 assocType = (Uml::Association_Type)assocTypeNum;
00393 }
00394 setAssocType( assocType );
00395
00396 Uml::IDType roleAObjID = STR2ID(element.attribute( "rolea", "-1" ));
00397 Uml::IDType roleBObjID = STR2ID(element.attribute( "roleb", "-1" ));
00398 if (assocType == at_Aggregation || assocType == at_Composition) {
00399
00400
00401 Uml::IDType tmp = roleAObjID;
00402 roleAObjID = roleBObjID;
00403 roleBObjID = tmp;
00404 }
00405
00406 UMLObject * objA = doc->findObjectById(roleAObjID);
00407 UMLObject * objB = doc->findObjectById(roleBObjID);
00408
00409 if(objA)
00410 getUMLRole(A)->setObject(objA);
00411 else
00412 return false;
00413
00414 if(objB)
00415 getUMLRole(B)->setObject(objB);
00416 else
00417 return false;
00418
00419 setMulti(element.attribute( "multia", "" ), A);
00420 setMulti(element.attribute( "multib", "" ), B);
00421
00422 setRoleName(element.attribute( "namea", "" ), A);
00423 setRoleName(element.attribute( "nameb", "" ), B);
00424
00425 setRoleDoc(element.attribute( "doca", "" ), A);
00426 setRoleDoc(element.attribute( "docb", "" ), B);
00427
00428
00429 QString visibilityA = element.attribute( "visibilitya", "0");
00430 QString visibilityB = element.attribute( "visibilityb", "0");
00431 if (visibilityA.toInt() > 0)
00432 setVisibility((Uml::Visibility::Value)visibilityA.toInt(), A);
00433 if (visibilityB.toInt() > 0)
00434 setVisibility((Uml::Visibility::Value)visibilityB.toInt(), B);
00435
00436
00437 QString changeabilityA = element.attribute( "changeabilitya", "0");
00438 QString changeabilityB = element.attribute( "changeabilityb", "0");
00439 if (changeabilityA.toInt() > 0)
00440 setChangeability ( (Changeability_Type) changeabilityA.toInt(), A);
00441 if (changeabilityB.toInt() > 0)
00442 setChangeability ( (Changeability_Type) changeabilityB.toInt(), B);
00443
00444 return true;
00445 }
00446
00447 UMLObject* UMLAssociation::getObject(Role_Type role) {
00448 return m_pRole[role]->getObject();
00449 }
00450
00451 Uml::IDType UMLAssociation::getObjectId(Role_Type role) {
00452 UMLRole *roleObj = m_pRole[role];
00453 UMLObject *o = roleObj->getObject();
00454 if (o == NULL) {
00455 QString auxID = roleObj->getSecondaryId();
00456 if (auxID.isEmpty()) {
00457 kError() << "UMLAssociation::getObjectId(" << role
00458 << "): getObject returns NULL" << endl;
00459 return Uml::id_None;
00460 } else {
00461 kDebug() << "UMLAssociation::getObjectId(" << role
00462 << "): using secondary ID " << auxID << endl;
00463 return STR2ID(auxID);
00464 }
00465 }
00466 return o->getID();
00467 }
00468
00469
00470
00471
00472
00473
00474
00475 Changeability_Type UMLAssociation::getChangeability(Role_Type role) const {
00476 return m_pRole[role]->getChangeability();
00477 }
00478
00479 Uml::Visibility UMLAssociation::getVisibility(Role_Type role) const {
00480 return m_pRole[role]->getVisibility();
00481 }
00482
00483 QString UMLAssociation::getMulti(Role_Type role) const {
00484 return m_pRole[role]->getMultiplicity();
00485 }
00486
00487 QString UMLAssociation::getRoleName(Role_Type role) const {
00488 return m_pRole[role]->getName();
00489 }
00490
00491 QString UMLAssociation::getRoleDoc(Role_Type role) const {
00492 return m_pRole[role]->getDoc();
00493 }
00494
00495 UMLRole * UMLAssociation::getUMLRole(Role_Type role) {
00496 return m_pRole[role];
00497 }
00498
00499 void UMLAssociation::setOldLoadMode(bool value ) {
00500 m_bOldLoadMode = value;
00501 }
00502
00503 bool UMLAssociation::getOldLoadMode() const {
00504 return m_bOldLoadMode;
00505 }
00506
00507 void UMLAssociation::setAssocType(Uml::Association_Type assocType) {
00508 m_AssocType = assocType;
00509 if(m_AssocType == at_UniAssociation)
00510 {
00511
00512
00513 #ifdef VERBOSE_DEBUGGING
00514 kDebug() << " A new uni-association has been created." << endl;
00515 #endif
00516 }
00517 UMLDoc *umldoc = UMLApp::app()->getDocument();
00518 if (! umldoc->loading())
00519 emit modified();
00520 }
00521
00522 void UMLAssociation::setObject(UMLObject *obj, Role_Type role) {
00523 m_pRole[role]->setObject(obj);
00524 }
00525
00526 void UMLAssociation::setVisibility(Uml::Visibility value, Role_Type role) {
00527 m_pRole[role]->setVisibility(value);
00528 }
00529
00530 void UMLAssociation::setChangeability(Changeability_Type value, Role_Type role) {
00531 m_pRole[role]->setChangeability(value);
00532 }
00533
00534 void UMLAssociation::setMulti(const QString &value, Role_Type role) {
00535 m_pRole[role]->setMultiplicity(value);
00536 }
00537
00538 void UMLAssociation::setRoleName(const QString &value, Role_Type role) {
00539 m_pRole[role]->setName(value);
00540 }
00541
00542 void UMLAssociation::setRoleDoc(const QString &doc, Role_Type role) {
00543 m_pRole[role]->setDoc(doc);
00544 }
00545
00546 QString UMLAssociation::ChangeabilityToString(Uml::Changeability_Type type) {
00547 switch (type) {
00548 case Uml::chg_Frozen:
00549 return "frozen";
00550 break;
00551 case Uml::chg_AddOnly:
00552 return "addOnly";
00553 break;
00554 case Uml::chg_Changeable:
00555 default:
00556 return "changeable";
00557 break;
00558 }
00559 }
00560
00561 void UMLAssociation::init(Association_Type type, UMLObject *roleAObj, UMLObject *roleBObj) {
00562 m_AssocType = type;
00563 m_BaseType = ot_Association;
00564 m_Name = "";
00565 m_bOldLoadMode = false;
00566 nrof_parent_widgets = -1;
00567 m_pUMLPackage = UMLApp::app()->getDocument()->currentRoot();
00568 m_pRole[Uml::A] = new UMLRole (this, roleAObj, Uml::A);
00569 m_pRole[Uml::B] = new UMLRole (this, roleBObj, Uml::B);
00570 }
00571
00572
00573 #include "association.moc"