00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "associationwidget.h"
00014
00015 #include <cstdlib>
00016 #include <cmath>
00017
00018 #include <qcanvas.h>
00019 #include <qvalidator.h>
00020 #include <kdebug.h>
00021 #include <klocale.h>
00022 #include <kinputdialog.h>
00023 #include <kcolordialog.h>
00024 #include <kapplication.h>
00025
00026 #include "activitywidget.h"
00027 #include "uml.h"
00028 #include "umlview.h"
00029 #include "umldoc.h"
00030 #include "umlwidget.h"
00031 #include "messagewidget.h"
00032 #include "umlrole.h"
00033 #include "listpopupmenu.h"
00034 #include "classifierwidget.h"
00035 #include "classifier.h"
00036 #include "entity.h"
00037 #include "attribute.h"
00038 #include "operation.h"
00039 #include "association.h"
00040 #include "assocrules.h"
00041 #include "floatingtextwidget.h"
00042 #include "objectwidget.h"
00043 #include "model_utils.h"
00044 #include "widget_utils.h"
00045 #include "dialogs/assocpropdlg.h"
00046 #include "optionstate.h"
00047
00048 using namespace Uml;
00049
00050
00051
00052
00053 AssociationWidget::AssociationWidget(UMLView *view)
00054 : WidgetBase(view)
00055 {
00056 init(view);
00057 }
00058
00059
00060 AssociationWidget::AssociationWidget(UMLView *view, UMLWidget* pWidgetA,
00061 Association_Type assocType, UMLWidget* pWidgetB,
00062 UMLAssociation *umlassoc )
00063 : WidgetBase(view)
00064 {
00065 init(view);
00066 if (umlassoc)
00067 setUMLAssociation(umlassoc);
00068 else
00069
00070 if (UMLAssociation::assocTypeHasUMLRepresentation(assocType)) {
00071 UMLObject* umlRoleA = pWidgetA->getUMLObject();
00072 UMLObject* umlRoleB = pWidgetB->getUMLObject();
00073 if (umlRoleA != NULL && umlRoleB != NULL) {
00074 bool swap;
00075
00076
00077
00078
00079
00080
00081
00082 UMLAssociation * myAssoc = m_umldoc->findAssociation( assocType, umlRoleA, umlRoleB, &swap );
00083 if (myAssoc != NULL) {
00084 if (assocType == at_Generalization) {
00085 kDebug() << " Ignoring second construction of same generalization"
00086 << endl;
00087 } else {
00088 kDebug() << " constructing a similar or exact same assoc " <<
00089 "as an already existing assoc (swap=" << swap << ")" << endl;
00090
00091 myAssoc = NULL;
00092 }
00093 }
00094 if (myAssoc == NULL)
00095 myAssoc = new UMLAssociation( assocType, umlRoleA, umlRoleB );
00096 setUMLAssociation(myAssoc);
00097 }
00098 }
00099
00100 setWidget(pWidgetA, A);
00101 setWidget(pWidgetB, B);
00102
00103 setAssocType(assocType);
00104
00105 calculateEndingPoints();
00106
00107
00108 setActivated(true);
00109
00110
00111 mergeAssociationDataIntoUMLRepresentation();
00112
00113
00114
00115
00116 if (isCollaboration()) {
00117
00118 int collabID = m_pView->generateCollaborationId();
00119 setName('m' + QString::number(collabID));
00120 }
00121 }
00122
00123 AssociationWidget::~AssociationWidget() {
00124 }
00125
00126 AssociationWidget& AssociationWidget::operator=(AssociationWidget & Other) {
00127 m_LinePath = Other.m_LinePath;
00128
00129 m_pView = Other.m_pView;
00130
00131 if (Other.m_pName) {
00132 m_pName = new FloatingTextWidget(m_pView);
00133 *m_pName = *(Other.m_pName);
00134 } else {
00135 m_pName = NULL;
00136 }
00137
00138 for (unsigned r = (unsigned)A; r <= (unsigned)B; r++) {
00139 WidgetRole& lhs = m_role[r];
00140 const WidgetRole& rhs = Other.m_role[r];
00141 lhs.m_nIndex = rhs.m_nIndex;
00142 lhs.m_nTotalCount = rhs.m_nTotalCount;
00143
00144 if (rhs.m_pMulti) {
00145 lhs.m_pMulti = new FloatingTextWidget(m_pView);
00146 *(lhs.m_pMulti) = *(rhs.m_pMulti);
00147 } else {
00148 lhs.m_pMulti = NULL;
00149 }
00150
00151 if (rhs.m_pRole) {
00152 lhs.m_pRole = new FloatingTextWidget(m_pView);
00153 *(lhs.m_pRole) = *(rhs.m_pRole);
00154 } else {
00155 lhs.m_pRole = NULL;
00156 }
00157
00158 if (rhs.m_pChangeWidget) {
00159 lhs.m_pChangeWidget = new FloatingTextWidget(m_pView);
00160 *(lhs.m_pChangeWidget) = *(rhs.m_pChangeWidget);
00161 } else {
00162 lhs.m_pChangeWidget = NULL;
00163 }
00164
00165 lhs.m_pWidget = rhs.m_pWidget;
00166 lhs.m_OldCorner = rhs.m_OldCorner;
00167 lhs.m_WidgetRegion = rhs.m_WidgetRegion;
00168 }
00169
00170 m_bActivated = Other.m_bActivated;
00171 m_unNameLineSegment = Other.m_unNameLineSegment;
00172 m_pMenu = Other.m_pMenu;
00173 setUMLAssociation(Other.getAssociation());
00174 m_bSelected = Other.m_bSelected;
00175 m_nMovingPoint = Other.m_nMovingPoint;
00176
00177 return *this;
00178 }
00179
00180 bool AssociationWidget::operator==(AssociationWidget & Other) {
00181 if( this == &Other )
00182 return true;
00183
00184 if( !m_pObject || !Other.m_pObject ) {
00185 if( !Other.m_pObject && m_pObject )
00186 return false;
00187 if( Other.m_pObject && !m_pObject )
00188 return false;
00189 } else if( m_pObject != Other.m_pObject )
00190 return false;
00191
00192 if (getAssocType() != Other.getAssocType())
00193 return false;
00194
00195 if (getWidgetID(A) != Other.getWidgetID(A))
00196 return false;
00197
00198 if (getWidgetID(B) != Other.getWidgetID(B))
00199 return false;
00200
00201 if (getWidget(A)->getBaseType() == Uml::wt_Object &&
00202 Other.getWidget(A)->getBaseType() == Uml::wt_Object) {
00203 ObjectWidget *ownA = static_cast<ObjectWidget*>(getWidget(A));
00204 ObjectWidget *otherA = static_cast<ObjectWidget*>(Other.getWidget(A));
00205 if (ownA->getLocalID() != otherA->getLocalID())
00206 return false;
00207 }
00208
00209 if (getWidget(B)->getBaseType() == Uml::wt_Object &&
00210 Other.getWidget(B)->getBaseType() == Uml::wt_Object) {
00211 ObjectWidget *ownB = static_cast<ObjectWidget*>(getWidget(B));
00212 ObjectWidget *otherB = static_cast<ObjectWidget*>(Other.getWidget(B));
00213 if (ownB->getLocalID() != otherB->getLocalID())
00214 return false;
00215 }
00216
00217
00218
00219
00220
00221 return (getName() == Other.getName());
00222 }
00223
00224 bool AssociationWidget::operator!=(AssociationWidget & Other) {
00225 return !(*this == Other);
00226 }
00227
00228 UMLAssociation * AssociationWidget::getAssociation () const {
00229 if (m_pObject == NULL || m_pObject->getBaseType() != ot_Association)
00230 return NULL;
00231 return static_cast<UMLAssociation*>(m_pObject);
00232 }
00233
00234 UMLAttribute * AssociationWidget::getAttribute () const {
00235 if (m_pObject == NULL)
00236 return NULL;
00237 Uml::Object_Type ot = m_pObject->getBaseType();
00238 if (ot != ot_Attribute && ot != ot_EntityAttribute)
00239 return NULL;
00240 return static_cast<UMLAttribute*>(m_pObject);
00241 }
00242
00243 FloatingTextWidget* AssociationWidget::getMultiWidget(Role_Type role) {
00244 return m_role[role].m_pMulti;
00245 }
00246
00247 QString AssociationWidget::getMulti(Role_Type role) const
00248 {
00249 if (m_role[role].m_pMulti == NULL)
00250 return "";
00251 return m_role[role].m_pMulti->getText();
00252 }
00253
00254 FloatingTextWidget* AssociationWidget::getNameWidget()
00255 {
00256 return m_pName;
00257 }
00258
00259 QString AssociationWidget::getName() const {
00260 if (m_pName == NULL)
00261 return "";
00262 return m_pName->getText();
00263 }
00264
00265 FloatingTextWidget* AssociationWidget::getRoleWidget(Role_Type role) {
00266 return m_role[role].m_pRole;
00267 }
00268
00269 FloatingTextWidget* AssociationWidget::getChangeWidget(Role_Type role) {
00270 return m_role[role].m_pChangeWidget;
00271 }
00272
00273 FloatingTextWidget* AssociationWidget::getTextWidgetByRole(Uml::Text_Role tr) {
00274 switch (tr) {
00275 case tr_MultiA:
00276 return m_role[A].m_pMulti;
00277 case tr_MultiB:
00278 return m_role[B].m_pMulti;
00279 case tr_Name:
00280 case tr_Coll_Message:
00281 return m_pName;
00282 case tr_RoleAName:
00283 return m_role[A].m_pRole;
00284 case tr_RoleBName:
00285 return m_role[B].m_pRole;
00286 case tr_ChangeA:
00287 return m_role[A].m_pChangeWidget;
00288 case tr_ChangeB:
00289 return m_role[B].m_pChangeWidget;
00290 default:
00291 break;
00292 }
00293 return NULL;
00294 }
00295
00296 QString AssociationWidget::getRoleName(Role_Type role) const {
00297 if (m_role[role].m_pRole == NULL)
00298 return "";
00299 return m_role[role].m_pRole->getText();
00300 }
00301
00302 QString AssociationWidget::getRoleDoc(Role_Type role) const {
00303 if (m_pObject == NULL || m_pObject->getBaseType() != ot_Association)
00304 return "";
00305 UMLAssociation *umla = static_cast<UMLAssociation*>(m_pObject);
00306 return umla->getRoleDoc(role);
00307 }
00308
00309 void AssociationWidget::setName(const QString &strName) {
00310
00311 UMLAssociation *umla = getAssociation();
00312 if (umla)
00313 umla->setName(strName);
00314
00315 bool newLabel = false;
00316 if(!m_pName) {
00317
00318 if (! FloatingTextWidget::isTextValid(strName))
00319 return;
00320
00321 newLabel = true;
00322 m_pName = new FloatingTextWidget(m_pView, CalculateNameType(tr_Name), strName);
00323 m_pName->setLink(this);
00324 } else {
00325 m_pName->setText(strName);
00326 if (! FloatingTextWidget::isTextValid(strName)) {
00327
00328 m_pView->removeWidget(m_pName);
00329 m_pName = NULL;
00330 return;
00331 }
00332 }
00333
00334 setTextPosition( tr_Name );
00335 if (newLabel) {
00336 m_pName->setActivated();
00337 m_pView->addWidget(m_pName);
00338 }
00339
00340 m_pName->show();
00341 }
00342
00343 void AssociationWidget::setFloatingText(Uml::Text_Role tr,
00344 const QString &text,
00345 FloatingTextWidget* &ft) {
00346 if (! FloatingTextWidget::isTextValid(text)) {
00347 if (ft) {
00348
00349 m_pView->removeWidget(ft);
00350 ft = NULL;
00351 }
00352 return;
00353 }
00354
00355 if (ft == NULL) {
00356 ft = new FloatingTextWidget(m_pView, tr, text);
00357 ft->setLink(this);
00358 ft->activate();
00359 setTextPosition(tr);
00360 m_pView->addWidget(ft);
00361 } else {
00362 bool newLabel = ft->getText().isEmpty();
00363 ft->setText(text);
00364 if (newLabel)
00365 setTextPosition(tr);
00366 }
00367
00368 ft->show();
00369 }
00370
00371 void AssociationWidget::setMulti(const QString &strMulti, Role_Type role) {
00372 Text_Role tr = (role == A ? tr_MultiA : tr_MultiB);
00373
00374 setFloatingText(tr, strMulti, m_role[role].m_pMulti);
00375
00376 if (m_pObject && m_pObject->getBaseType() == ot_Association)
00377 getAssociation()->setMulti(strMulti, role);
00378 }
00379
00380 void AssociationWidget::setRoleName (const QString &strRole, Role_Type role) {
00381 Association_Type type = getAssocType();
00382
00383 if (!AssocRules::allowRole(type)) {
00384 return;
00385 }
00386
00387 Text_Role tr = (role == A ? tr_RoleAName : tr_RoleBName);
00388 setFloatingText(tr, strRole, m_role[role].m_pRole);
00389 if (m_role[role].m_pRole) {
00390 Uml::Visibility vis = getVisibility(role);
00391 if (FloatingTextWidget::isTextValid(m_role[role].m_pRole->getText())) {
00392 m_role[role].m_pRole->setPreText(vis.toString(true));
00393
00394 } else {
00395 m_role[role].m_pRole->setPreText("");
00396
00397 }
00398 }
00399
00400
00401 if (m_pObject && m_pObject->getBaseType() == ot_Association)
00402 getAssociation()->setRoleName(strRole, role);
00403 }
00404
00405 void AssociationWidget::setRoleDoc (const QString &doc, Role_Type role) {
00406 if (m_pObject && m_pObject->getBaseType() == ot_Association)
00407 getAssociation()->setRoleDoc(doc, role);
00408 else
00409 m_role[role].m_RoleDoc = doc;
00410 }
00411
00412 void AssociationWidget::setMessageText(FloatingTextWidget *ft) {
00413 QString message;
00414 if (isCollaboration()) {
00415 if (m_pObject != NULL) {
00416 message = getMulti(A) + ": " + getOperationText(m_pView);
00417 } else {
00418 message = getMulti(A) + ": " + getName();
00419 }
00420 } else {
00421 message = getName();
00422 }
00423 ft->setText(message);
00424 }
00425
00426 Uml::Visibility AssociationWidget::getVisibility(Role_Type role) const {
00427 const UMLAssociation *assoc = getAssociation();
00428 if (assoc)
00429 return assoc->getVisibility(role);
00430 const UMLAttribute *attr = getAttribute();
00431 if (attr)
00432 return attr->getVisibility();
00433 return m_role[role].m_Visibility;
00434 }
00435
00436 void AssociationWidget::setVisibility(Uml::Visibility value, Role_Type role)
00437 {
00438 if (value == getVisibility(role))
00439 return;
00440 if (m_pObject) {
00441
00442 const Uml::Object_Type ot = m_pObject->getBaseType();
00443 if (ot == ot_Association)
00444 getAssociation()->setVisibility(value, role);
00445 else if (ot == ot_Attribute)
00446 getAttribute()->setVisibility(value);
00447 }
00448 m_role[role].m_Visibility = value;
00449
00450 if (m_role[role].m_pRole) {
00451 QString scopeString = value.toString(true);
00452 m_role[role].m_pRole->setPreText(scopeString);
00453 }
00454 }
00455
00456 Changeability_Type AssociationWidget::getChangeability(Role_Type role) const
00457 {
00458 if (m_pObject == NULL || m_pObject->getBaseType() != ot_Association)
00459 return m_role[role].m_Changeability;
00460 UMLAssociation *umla = static_cast<UMLAssociation*>(m_pObject);
00461 return umla->getChangeability(role);
00462 }
00463
00464 void AssociationWidget::setChangeability (Changeability_Type value, Role_Type role)
00465 {
00466 if (value == getChangeability(role))
00467 return;
00468 QString changeString = UMLAssociation::ChangeabilityToString(value);
00469 if (m_pObject && m_pObject->getBaseType() == ot_Association)
00470 getAssociation()->setChangeability(value, role);
00471 m_role[role].m_Changeability = value;
00472
00473 setChangeWidget(changeString, role);
00474 }
00475
00476 void AssociationWidget::setChangeWidget(const QString &strChangeWidget, Role_Type role) {
00477 bool newLabel = false;
00478 Text_Role tr = (role == A ? tr_ChangeA : tr_ChangeB);
00479
00480 if(!m_role[role].m_pChangeWidget) {
00481
00482 if (strChangeWidget.isEmpty())
00483 return;
00484
00485 newLabel = true;
00486 m_role[role].m_pChangeWidget = new FloatingTextWidget(m_pView, tr, strChangeWidget);
00487 m_role[role].m_pChangeWidget->setLink(this);
00488 m_pView->addWidget(m_role[role].m_pChangeWidget);
00489 m_role[role].m_pChangeWidget->setPreText("{");
00490 m_role[role].m_pChangeWidget->setPostText("}");
00491 } else {
00492 if (m_role[role].m_pChangeWidget->getText().isEmpty()) {
00493 newLabel = true;
00494 }
00495 m_role[role].m_pChangeWidget->setText(strChangeWidget);
00496 }
00497 m_role[role].m_pChangeWidget->setActivated();
00498
00499 if (newLabel) {
00500 setTextPosition( tr );
00501 }
00502
00503 if(FloatingTextWidget::isTextValid(m_role[role].m_pChangeWidget->getText()))
00504 m_role[role].m_pChangeWidget -> show();
00505 else
00506 m_role[role].m_pChangeWidget -> hide();
00507 }
00508
00509 bool AssociationWidget::linePathStartsAt(const UMLWidget* widget) {
00510 QPoint lpStart = m_LinePath.getPoint(0);
00511 int startX = lpStart.x();
00512 int startY = lpStart.y();
00513 int wX = widget->getX();
00514 int wY = widget->getY();
00515 int wWidth = widget->getWidth();
00516 int wHeight = widget->getHeight();
00517 bool result = (startX >= wX && startX <= wX + wWidth &&
00518 startY >= wY && startY <= wY + wHeight);
00519 return result;
00520 }
00521
00522 void AssociationWidget::setText(FloatingTextWidget *ft, const QString &text) {
00523 Uml::Text_Role role = ft->getRole();
00524 switch (role) {
00525 case tr_Name:
00526 setName(text);
00527 break;
00528 case tr_RoleAName:
00529 setRoleName(text, A);
00530 break;
00531 case tr_RoleBName:
00532 setRoleName(text, B);
00533 break;
00534 case tr_MultiA:
00535 setMulti(text, A);
00536 break;
00537 case tr_MultiB:
00538 setMulti(text, B);
00539 break;
00540 default:
00541 break;
00542 }
00543 }
00544
00545 bool AssociationWidget::activate() {
00546 if (m_pObject == NULL &&
00547 UMLAssociation::assocTypeHasUMLRepresentation(m_AssocType)) {
00548 UMLObject *myObj = m_umldoc->findObjectById(m_nId);
00549 if (myObj == NULL) {
00550 kError() << "AssociationWidget::activate: cannot find UMLObject "
00551 << ID2STR(m_nId) << endl;
00552 return false;
00553 } else {
00554 const Uml::Object_Type ot = myObj->getBaseType();
00555 if (ot == ot_Association) {
00556 UMLAssociation * myAssoc = static_cast<UMLAssociation*>(myObj);
00557 setUMLAssociation(myAssoc);
00558 m_LinePath.setAssocType( myAssoc->getAssocType() );
00559 } else {
00560 setUMLObject(myObj);
00561 setAssocType(m_AssocType);
00562 }
00563 }
00564 }
00565
00566 if (m_bActivated)
00567 return true;
00568
00569 Association_Type type = getAssocType();
00570
00571 if (m_role[A].m_pWidget == NULL)
00572 setWidget(m_pView->findWidget(getWidgetID(A)), A);
00573 if (m_role[B].m_pWidget == NULL)
00574 setWidget(m_pView->findWidget(getWidgetID(B)), B);
00575
00576 if(!m_role[A].m_pWidget || !m_role[B].m_pWidget) {
00577 kDebug() << "Can't make association" << endl;
00578 return false;
00579 }
00580
00581 calculateEndingPoints();
00582 m_LinePath.activate();
00583
00584 if (AssocRules::allowRole(type)) {
00585 for (unsigned r = A; r <= B; r++) {
00586 WidgetRole& robj = m_role[r];
00587 if (robj.m_pRole == NULL)
00588 continue;
00589 robj.m_pRole->setLink(this);
00590 Text_Role tr = (r == A ? tr_RoleAName : tr_RoleBName);
00591 robj.m_pRole->setRole(tr);
00592 Uml::Visibility vis = getVisibility((Role_Type)r);
00593 robj.m_pRole->setPreText(vis.toString(true));
00594
00595 if (FloatingTextWidget::isTextValid(robj.m_pRole->getText()))
00596 robj.m_pRole -> show();
00597 else
00598 robj.m_pRole -> hide();
00599 if (m_pView->getType() == dt_Collaboration)
00600 robj.m_pRole->setUMLObject(robj.m_pWidget->getUMLObject());
00601 robj.m_pRole->activate();
00602 }
00603 }
00604
00605 if( m_pName != NULL ) {
00606 m_pName->setLink(this);
00607 m_pName->setRole( CalculateNameType(tr_Name) );
00608
00609 if ( FloatingTextWidget::isTextValid(m_pName->getText()) ) {
00610 m_pName-> show();
00611 } else {
00612 m_pName-> hide();
00613 }
00614 m_pName->activate();
00615 calculateNameTextSegment();
00616 }
00617
00618 for (unsigned r = A; r <= B; r++) {
00619 WidgetRole& robj = m_role[r];
00620
00621 FloatingTextWidget* pMulti = robj.m_pMulti;
00622 if (pMulti != NULL &&
00623 AssocRules::allowMultiplicity(type, robj.m_pWidget->getBaseType())) {
00624 pMulti->setLink(this);
00625 Text_Role tr = (r == A ? tr_MultiA : tr_MultiB);
00626 pMulti->setRole(tr);
00627 if (FloatingTextWidget::isTextValid(pMulti->getText()))
00628 pMulti -> show();
00629 else
00630 pMulti -> hide();
00631 pMulti->activate();
00632 }
00633
00634 FloatingTextWidget* pChangeWidget = robj.m_pChangeWidget;
00635 if (pChangeWidget != NULL ) {
00636 pChangeWidget->setLink(this);
00637 Text_Role tr = (r == A ? tr_ChangeA : tr_ChangeB);
00638 pChangeWidget->setRole(tr);
00639 if (FloatingTextWidget::isTextValid(pChangeWidget->getText()))
00640 pChangeWidget -> show();
00641 else
00642 pChangeWidget -> hide ();
00643 pChangeWidget->activate();
00644 }
00645 }
00646
00647
00648 if (m_pAssocClassWidget && !m_pAssocClassLine) {
00649 createAssocClassLine();
00650 }
00651
00652 m_bActivated = true;
00653 return true;
00654 }
00655
00657 Uml::Text_Role AssociationWidget::CalculateNameType(Text_Role defaultRole) {
00658
00659 Text_Role result = defaultRole;
00660 if( m_pView -> getType() == dt_Collaboration ) {
00661 if(m_role[A].m_pWidget == m_role[B].m_pWidget) {
00662 result = tr_Coll_Message;
00663 } else {
00664 result = tr_Coll_Message;
00665 }
00666 } else if( m_pView -> getType() == dt_Sequence ) {
00667 if(m_role[A].m_pWidget == m_role[B].m_pWidget) {
00668 result = tr_Seq_Message_Self;
00669 } else {
00670 result = tr_Seq_Message;
00671 }
00672 }
00673
00674 return result;
00675 }
00676
00677 UMLWidget* AssociationWidget::getWidget(Role_Type role) {
00678 return m_role[role].m_pWidget;
00679 }
00680
00681 bool AssociationWidget::setWidgets( UMLWidget* widgetA,
00682 Association_Type assocType,
00683 UMLWidget* widgetB) {
00684
00685
00686
00687 if ((m_role[A].m_pWidget && (m_role[A].m_pWidget != widgetA)) ||
00688 (m_role[B].m_pWidget && (m_role[B].m_pWidget != widgetB))) {
00689 return false;
00690 }
00691 setWidget(widgetA, A);
00692 setAssocType(assocType);
00693 setWidget(widgetB, B);
00694
00695 calculateEndingPoints();
00696 return true;
00697 }
00698
00701 bool AssociationWidget::checkAssoc(UMLWidget * widgetA, UMLWidget *widgetB) {
00702 return (widgetA == m_role[A].m_pWidget && widgetB == m_role[B].m_pWidget);
00703 }
00704
00706 void AssociationWidget::cleanup() {
00707
00708
00709 if(m_role[A].m_nTotalCount > 2)
00710 updateAssociations(m_role[A].m_nTotalCount - 1, m_role[A].m_WidgetRegion, A);
00711 if(m_role[B].m_nTotalCount > 2)
00712 updateAssociations(m_role[B].m_nTotalCount - 1, m_role[B].m_WidgetRegion, B);
00713
00714 for (unsigned r = A; r <= B; r++) {
00715 WidgetRole& robj = m_role[r];
00716
00717 if(robj.m_pWidget) {
00718 robj.m_pWidget->removeAssoc(this);
00719 robj.m_pWidget = 0;
00720 }
00721 if(robj.m_pRole) {
00722 m_pView->removeWidget(robj.m_pRole);
00723 robj.m_pRole = 0;
00724 }
00725 if(robj.m_pMulti) {
00726 m_pView->removeWidget(robj.m_pMulti);
00727 robj.m_pMulti = 0;
00728 }
00729 if(robj.m_pChangeWidget) {
00730 m_pView->removeWidget(robj.m_pChangeWidget);
00731 robj.m_pChangeWidget = 0;
00732 }
00733 }
00734
00735 if(m_pName) {
00736 m_pView->removeWidget(m_pName);
00737 m_pName = 0;
00738 }
00739
00740 if (m_pObject && m_pObject->getBaseType() == ot_Association) {
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756 setUMLAssociation(0);
00757 }
00758
00759 m_LinePath.cleanup();
00760 removeAssocClassLine();
00761 }
00762
00763 void AssociationWidget::setUMLAssociation (UMLAssociation * assoc)
00764 {
00765 if (m_pObject && m_pObject->getBaseType() == ot_Association) {
00766 UMLAssociation *umla = getAssociation();
00767
00768
00769
00770 if (assoc && umla == assoc)
00771 return;
00772
00773
00774 umla->nrof_parent_widgets--;
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806 if (umla->nrof_parent_widgets == 0) {
00807
00808 }
00809
00810 m_pObject = NULL;
00811 }
00812
00813 if(assoc) {
00814 m_pObject = assoc;
00815
00816
00817 if(assoc->nrof_parent_widgets < 0)
00818 assoc->nrof_parent_widgets = 0;
00819
00820 assoc->nrof_parent_widgets++;
00821 connect(assoc, SIGNAL(modified()), this, SLOT(syncToModel()));
00822 }
00823
00824 }
00825
00826
00828 bool AssociationWidget::contains(UMLWidget* widget) {
00829 return (widget == m_role[A].m_pWidget || widget == m_role[B].m_pWidget);
00830 }
00831
00832 bool AssociationWidget::isCollaboration() {
00833 Uml::Association_Type at = getAssocType();
00834 return (at == at_Coll_Message || at == at_Coll_Message_Self);
00835 }
00836
00837 Association_Type AssociationWidget::getAssocType() const {
00838 if (m_pObject == NULL || m_pObject->getBaseType() != ot_Association)
00839 return m_AssocType;
00840 UMLAssociation *umla = static_cast<UMLAssociation*>(m_pObject);
00841 return umla->getAssocType();
00842 }
00843
00845 void AssociationWidget::setAssocType(Association_Type type) {
00846 if (m_pObject && m_pObject->getBaseType() == ot_Association)
00847 getAssociation()->setAssocType(type);
00848 m_AssocType = type;
00849 m_LinePath.setAssocType(type);
00850
00851
00852
00853
00854
00855 if( !AssocRules::allowMultiplicity(type, getWidget(A)->getBaseType()) ) {
00856 if (m_role[A].m_pMulti) {
00857 m_role[A].m_pMulti->setName("");
00858 }
00859 if (m_role[B].m_pMulti) {
00860 m_role[B].m_pMulti->setName("");
00861 }
00862 }
00863 if( !AssocRules::allowRole( type ) ) {
00864 if (m_role[A].m_pRole) {
00865 m_role[A].m_pRole->setName("");
00866 }
00867 if (m_role[B].m_pRole) {
00868 m_role[B].m_pRole->setName("");
00869 }
00870 setRoleDoc("", A);
00871 setRoleDoc("", B);
00872 }
00873 }
00874
00875 Uml::IDType AssociationWidget::getWidgetID(Role_Type role) const {
00876 if (m_role[role].m_pWidget == NULL) {
00877 if (m_pObject && m_pObject->getBaseType() == ot_Association) {
00878 UMLAssociation *umla = static_cast<UMLAssociation*>(m_pObject);
00879 return umla->getObjectId(role);
00880 }
00881 kError() << "AssociationWidget::getWidgetID(): m_pWidget is NULL" << endl;
00882 return Uml::id_None;
00883 }
00884 if (m_role[role].m_pWidget->getBaseType() == Uml::wt_Object)
00885 return static_cast<ObjectWidget*>(m_role[role].m_pWidget)->getLocalID();
00886 Uml::IDType id = m_role[role].m_pWidget->getID();
00887 return id;
00888 }
00889
00891 QString AssociationWidget::toString() {
00892 QString string = "";
00893
00894 if(m_role[A].m_pWidget) {
00895 string = m_role[A].m_pWidget -> getName();
00896 }
00897 string.append(":");
00898
00899 if(m_role[A].m_pRole) {
00900 string += m_role[A].m_pRole -> getText();
00901 }
00902 string.append(":");
00903 string.append( UMLAssociation::typeAsString(getAssocType()) );
00904 string.append(":");
00905 if(m_role[B].m_pWidget) {
00906 string += m_role[B].m_pWidget -> getName();
00907 }
00908
00909 string.append(":");
00910 if(m_role[B].m_pRole) {
00911 string += m_role[B].m_pRole -> getText();
00912 }
00913
00914 return string;
00915 }
00916
00917 void AssociationWidget::mouseDoubleClickEvent(QMouseEvent * me) {
00918 if (me->button() != Qt::RightButton && me->button() != Qt::LeftButton)
00919 return;
00920 int i = m_LinePath.onLinePath(me->pos());
00921 if (i == -1) {
00922 m_LinePath.setSelected(false);
00923 return;
00924 }
00925 if (me->button() != Qt::LeftButton)
00926 return;
00927 const QPoint mp(me->pos());
00928
00929 if (! m_LinePath.isPoint(i, mp, POINT_DELTA)) {
00930 m_LinePath.insertPoint(i + 1, mp);
00931 if (m_nLinePathSegmentIndex == i) {
00932 QPoint segStart = m_LinePath.getPoint(i);
00933 QPoint segEnd = m_LinePath.getPoint(i + 2);
00934 const int midSegX = segStart.x() + (segEnd.x() - segStart.x()) / 2;
00935 const int midSegY = segStart.y() + (segEnd.y() - segStart.y()) / 2;
00936
00937
00938
00939
00940
00941
00942
00943
00944 if (midSegX > mp.x() || midSegY < mp.y()) {
00945 m_nLinePathSegmentIndex++;
00946 kDebug() << "AssociationWidget::mouseDoubleClickEvent: "
00947 << "setting m_nLinePathSegmentIndex to "
00948 << m_nLinePathSegmentIndex << endl;
00949 computeAssocClassLine();
00950 }
00951 }
00952 } else {
00953
00954 m_LinePath.setSelected( false );
00955
00956
00957 if (m_LinePath.removePoint(i, mp, POINT_DELTA)) {
00958
00959
00960 const int numberOfLines = m_LinePath.count() - 1;
00961 if (m_nLinePathSegmentIndex >= numberOfLines) {
00962 m_nLinePathSegmentIndex = numberOfLines - 1;
00963 computeAssocClassLine();
00964 }
00965 }
00966
00967
00968 m_LinePath.setSelected( true );
00969 }
00970
00971 m_LinePath.update();
00972
00973 calculateNameTextSegment();
00974 m_umldoc->setModified(true);
00975 }
00976
00977 void AssociationWidget::moveEvent(QMoveEvent* me) {
00978
00979
00980
00982 if ( m_umldoc->loading() ) {
00983
00984
00985
00986
00987 kWarning() << "AssociationWidget::moveEvent() called during load of XMI for ViewType: " << m_pView -> getType()
00988 << ", and BaseType: " << getBaseType()
00989 << endl;
00990 return;
00991 }
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003 QPoint oldNamePoint = calculateTextPosition(tr_Name);
01004 QPoint oldMultiAPoint = calculateTextPosition(tr_MultiA);
01005 QPoint oldMultiBPoint = calculateTextPosition(tr_MultiB);
01006 QPoint oldChangeAPoint = calculateTextPosition(tr_ChangeA);
01007 QPoint oldChangeBPoint = calculateTextPosition(tr_ChangeB);
01008 QPoint oldRoleAPoint = calculateTextPosition(tr_RoleAName);
01009 QPoint oldRoleBPoint = calculateTextPosition(tr_RoleBName);
01010
01011 m_LinePath.setPoint( m_nMovingPoint, me->pos() );
01012 int pos = m_LinePath.count() - 1;
01013
01014 if ( m_nMovingPoint == 1 || (m_nMovingPoint == pos-1) ) {
01015 calculateEndingPoints();
01016 }
01017 if (m_role[A].m_pChangeWidget && (m_nMovingPoint == 1)) {
01018 setTextPositionRelatively(tr_ChangeA, oldChangeAPoint);
01019 }
01020 if (m_role[B].m_pChangeWidget && (m_nMovingPoint == 1)) {
01021 setTextPositionRelatively(tr_ChangeB, oldChangeBPoint);
01022 }
01023 if (m_role[A].m_pMulti && (m_nMovingPoint == 1)) {
01024 setTextPositionRelatively(tr_MultiA, oldMultiAPoint);
01025 }
01026 if (m_role[B].m_pMulti && (m_nMovingPoint == pos-1)) {
01027 setTextPositionRelatively(tr_MultiB, oldMultiBPoint);
01028 }
01029
01030 if (m_pName) {
01031 if(m_nMovingPoint == (int)m_unNameLineSegment ||
01032 m_nMovingPoint - 1 == (int)m_unNameLineSegment) {
01033 setTextPositionRelatively(tr_Name, oldNamePoint);
01034 }
01035 }
01036
01037 if (m_role[A].m_pRole) {
01038 setTextPositionRelatively(tr_RoleAName, oldRoleAPoint);
01039 }
01040 if (m_role[B].m_pRole) {
01041 setTextPositionRelatively(tr_RoleBName, oldRoleBPoint);
01042 }
01043 }
01044
01045
01050 void AssociationWidget::calculateEndingPoints() {
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077 UMLWidget *pWidgetA = m_role[A].m_pWidget;
01078 UMLWidget *pWidgetB = m_role[B].m_pWidget;
01079 if (!pWidgetA || !pWidgetB)
01080 return;
01081 m_role[A].m_OldCorner.setX( pWidgetA->getX() );
01082 m_role[A].m_OldCorner.setY( pWidgetA->getY() );
01083 m_role[B].m_OldCorner.setX( pWidgetB->getX() );
01084 m_role[B].m_OldCorner.setY( pWidgetB->getY() );
01085 uint size = m_LinePath.count();
01086 if(size < 2)
01087 m_LinePath.setStartEndPoints( m_role[A].m_OldCorner, m_role[B].m_OldCorner );
01088
01089
01090
01091
01092
01093
01094 if (pWidgetA == pWidgetB && size < 4) {
01095 const int DISTANCE = 50;
01096 int x = pWidgetA -> getX();
01097 int y = pWidgetA -> getY();
01098 int h = pWidgetA -> getHeight();
01099 int w = pWidgetA -> getWidth();
01100
01101 if( y - DISTANCE > 0 ) {
01102 m_LinePath.setStartEndPoints( QPoint( x + w / 4, y ) , QPoint( x + w * 3 / 4, y ) );
01103 m_LinePath.insertPoint( 1, QPoint( x + w / 4, y - DISTANCE ) );
01104 m_LinePath.insertPoint( 2 ,QPoint( x + w * 3 / 4, y - DISTANCE ) );
01105 m_role[A].m_WidgetRegion = m_role[B].m_WidgetRegion = North;
01106 } else {
01107 m_LinePath.setStartEndPoints( QPoint( x + w / 4, y + h ), QPoint( x + w * 3 / 4, y + h ) );
01108 m_LinePath.insertPoint( 1, QPoint( x + w / 4, y + h + DISTANCE ) );
01109 m_LinePath.insertPoint( 2, QPoint( x + w * 3 / 4, y + h + DISTANCE ) );
01110 m_role[A].m_WidgetRegion = m_role[B].m_WidgetRegion = South;
01111 }
01112 return;
01113 }
01114
01115
01116
01117 int xB = pWidgetB->getX() + pWidgetB->getWidth() / 2;
01118 int yB = pWidgetB->getY() + pWidgetB->getHeight() / 2;
01119 if( size > 2 ) {
01120 QPoint p = m_LinePath.getPoint( 1 );
01121 xB = p.x();
01122 yB = p.y();
01123 }
01124 doUpdates(xB, yB, A);
01125
01126
01127
01128
01129 int xA = pWidgetA->getX() + pWidgetA->getWidth() / 2;
01130 int yA = pWidgetA->getY() + pWidgetA->getHeight() / 2;
01131 if (size > 2 ) {
01132 QPoint p = m_LinePath.getPoint( size - 2 );
01133 xA = p.x();
01134 yA = p.y();
01135 }
01136 doUpdates( xA, yA, B );
01137
01138 computeAssocClassLine();
01139 }
01140
01141 void AssociationWidget::doUpdates(int otherX, int otherY, Role_Type role) {
01142
01143 Region oldRegion = m_role[role].m_WidgetRegion;
01144 UMLWidget *pWidget = m_role[role].m_pWidget;
01145 QRect rc(pWidget->getX(), pWidget->getY(),
01146 pWidget->getWidth(), pWidget->getHeight());
01147 Region& region = m_role[role].m_WidgetRegion;
01148 region = findPointRegion( rc, otherX, otherY);
01149
01150 switch( region ) {
01151 case NorthWest:
01152 region = North;
01153 break;
01154 case NorthEast:
01155 region = East;
01156 break;
01157 case SouthEast:
01158 region = South;
01159 break;
01160 case SouthWest:
01161 case Center:
01162 region = West;
01163 break;
01164 default:
01165 break;
01166 }
01167 int regionCount = getRegionCount(region, role) + 2;
01168 int totalCount = m_role[role].m_nTotalCount;
01169 if( oldRegion != region ) {
01170 updateRegionLineCount( regionCount - 1, regionCount, region, role );
01171 updateAssociations( totalCount - 1, oldRegion, role );
01172 } else if( totalCount != regionCount ) {
01173 updateRegionLineCount( regionCount - 1, regionCount, region, role );
01174 } else {
01175 updateRegionLineCount( m_role[role].m_nIndex, totalCount, region, role );
01176 }
01177 updateAssociations( regionCount, region, role );
01178 }
01179
01181 bool AssociationWidget::isActivated() {
01182 return m_bActivated;
01183 }
01184
01186 void AssociationWidget::setActivated(bool active ) {
01187 m_bActivated = active;
01188 }
01189
01190 void AssociationWidget::syncToModel()
01191 {
01192 UMLAssociation *uml = getAssociation();
01193
01194 if (uml == NULL) {
01195 UMLAttribute *attr = getAttribute();
01196 if (attr == NULL)
01197 return;
01198 setVisibility(attr->getVisibility(), B);
01199 setRoleName(attr->getName(), B);
01200 return;
01201 }
01202
01203 uml->blockSignals(true);
01204
01205 setName(uml->getName());
01206 setRoleName(uml->getRoleName(A), A);
01207 setRoleName(uml->getRoleName(B), B);
01208 setVisibility(uml->getVisibility(A), A);
01209 setVisibility(uml->getVisibility(B), B);
01210 setChangeability(uml->getChangeability(A), A);
01211 setChangeability(uml->getChangeability(B), B);
01212 setMulti(uml->getMulti(A), A);
01213 setMulti(uml->getMulti(B), B);
01214
01215 uml->blockSignals(false);
01216 }
01217
01218
01219 void AssociationWidget::mergeAssociationDataIntoUMLRepresentation()
01220 {
01221 UMLAssociation *umlassoc = getAssociation();
01222 UMLAttribute *umlattr = getAttribute();
01223 if (umlassoc == NULL && umlattr == NULL)
01224 return;
01225
01226
01227 m_pObject->blockSignals(true);
01228
01229
01230
01231
01232
01233
01234
01235 FloatingTextWidget *text = getNameWidget();
01236 if (text)
01237 m_pObject->setName(text->getText());
01238
01239 text = getRoleWidget(A);
01240 if (text && umlassoc)
01241 umlassoc->setRoleName(text->getText(), A);
01242
01243 text = getRoleWidget(B);
01244 if (text) {
01245 if (umlassoc)
01246 umlassoc->setRoleName(text->getText(), B);
01247 else if (umlattr)
01248 umlattr->setName(text->getText());
01249 }
01250
01251 text = getMultiWidget(A);
01252 if (text && umlassoc)
01253 umlassoc->setMulti(text->getText(), A);
01254
01255 text = getMultiWidget(B);
01256 if (text && umlassoc)
01257 umlassoc->setMulti(text->getText(), B);
01258
01259
01260 m_pObject->blockSignals(false);
01261 }
01262
01263 void AssociationWidget::saveIdealTextPositions() {
01264 m_oldNamePoint = calculateTextPosition(tr_Name);
01265 m_oldMultiAPoint = calculateTextPosition(tr_MultiA);
01266 m_oldMultiBPoint = calculateTextPosition(tr_MultiB);
01267 m_oldChangeAPoint = calculateTextPosition(tr_ChangeA);
01268 m_oldChangeBPoint = calculateTextPosition(tr_ChangeB);
01269 m_oldRoleAPoint = calculateTextPosition(tr_RoleAName);
01270 m_oldRoleBPoint = calculateTextPosition(tr_RoleBName);
01271 }
01272
01274 void AssociationWidget::widgetMoved(UMLWidget* widget, int x, int y ) {
01275
01276
01277
01279 if ( m_umldoc->loading() ) {
01280
01281
01282
01283
01284 kDebug() << "AssociationWidget::widgetMoved() called during load of XMI for ViewType: " << m_pView -> getType()
01285 << ", and BaseType: " << getBaseType()
01286 << endl;
01287 return;
01288 }
01289
01290 int dx = m_role[A].m_OldCorner.x() - x;
01291 int dy = m_role[A].m_OldCorner.y() - y;
01292 uint size = m_LinePath.count();
01293 uint pos = size - 1;
01294 calculateEndingPoints();
01295
01296
01297 if( m_role[A].m_pWidget == m_role[B].m_pWidget ) {
01298 for( int i=1 ; i < (int)pos ; i++ ) {
01299 QPoint p = m_LinePath.getPoint( i );
01300 int newX = p.x() - dx;
01301 int newY = p.y() - dy;
01302
01303 if(newX < 0)
01304 newX = 0;
01305
01306 if(newY < 0)
01307 newY = 0;
01308 newX = m_pView -> snappedX( newX );
01309 newY = m_pView -> snappedY( newY );
01310 p.setX( newX );
01311 p.setY( newY );
01312 m_LinePath.setPoint( i, p );
01313 }
01314
01315 if ( m_pName && !m_pName->getSelected() ) {
01316 setTextPositionRelatively(tr_Name, m_oldNamePoint);
01317 }
01318
01319 }
01320 else if (m_role[A].m_pWidget==widget) {
01321 if (m_pName && m_unNameLineSegment == 0 && !m_pName->getSelected() ) {
01322
01323 setTextPositionRelatively(tr_Name, m_oldNamePoint);
01324 }
01325 }
01326 else if (m_role[B].m_pWidget==widget) {
01327 if (m_pName && (m_unNameLineSegment == pos-1) && !m_pName->getSelected() ) {
01328
01329 setTextPositionRelatively(tr_Name, m_oldNamePoint);
01330 }
01331 }
01332
01333 if ( m_role[A].m_pRole && !m_role[A].m_pRole->getSelected() ) {
01334 setTextPositionRelatively(tr_RoleAName, m_oldRoleAPoint);
01335 }
01336 if ( m_role[B].m_pRole && !m_role[B].m_pRole->getSelected() ) {
01337 setTextPositionRelatively(tr_RoleBName, m_oldRoleBPoint);
01338 }
01339 if ( m_role[A].m_pMulti && !m_role[A].m_pMulti->getSelected() ) {
01340 setTextPositionRelatively(tr_MultiA, m_oldMultiAPoint);
01341 }
01342 if ( m_role[B].m_pMulti && !m_role[B].m_pMulti->getSelected() ) {
01343 setTextPositionRelatively(tr_MultiB, m_oldMultiBPoint);
01344 }
01345 if ( m_role[A].m_pChangeWidget && !m_role[A].m_pChangeWidget->getSelected() ) {
01346 setTextPositionRelatively(tr_ChangeA, m_oldChangeAPoint);
01347 }
01348 if ( m_role[B].m_pChangeWidget && !m_role[B].m_pChangeWidget->getSelected() ) {
01349 setTextPositionRelatively(tr_ChangeB, m_oldChangeBPoint);
01350 }
01351 }
01352
01365 AssociationWidget::Region AssociationWidget::findPointRegion(QRect Rect, int PosX, int PosY) {
01366 float w = (float)Rect.width();
01367 float h = (float)Rect.height();
01368 float x = (float)Rect.x();
01369 float y = (float)Rect.y();
01370 float Slope2 = w / h;
01371 float Slope1 = Slope2*(float)(-1);
01372 float b1 = x + w - ( Slope1* y );
01373 float b2 = x - ( Slope2* y );
01374
01375 float eval1 = Slope1 * (float)PosY + b1;
01376 float eval2 = Slope2 *(float)PosY + b2;
01377
01378 Region result = Error;
01379
01380 if(eval1 > PosX && eval2 > PosX) {
01381 result = West;
01382 }
01383
01384 else if (eval1 > PosX && eval2 < PosX) {
01385 result = North;
01386 }
01387
01388 else if (eval1 < PosX && eval2 < PosX) {
01389 result = East;
01390 }
01391
01392 else if (eval1 < PosX && eval2 > PosX) {
01393 result = South;
01394 }
01395
01396 else if (eval1 == PosX && eval2 < PosX) {
01397 result = NorthWest;
01398 }
01399
01400 else if (eval1 < PosX && eval2 == PosX) {
01401 result = NorthEast;
01402 }
01403
01404 else if (eval1 == PosX && eval2 > PosX) {
01405 result = SouthEast;
01406 }
01407
01408 else if (eval1 > PosX && eval2 == PosX) {
01409 result = SouthWest;
01410 }
01411
01412 else if (eval1 == PosX && eval2 == PosX) {
01413 result = Center;
01414 }
01415 return result;
01416 }
01417
01418 QPoint AssociationWidget::swapXY(const QPoint &p) {
01419 QPoint swapped( p.y(), p.x() );
01420 return swapped;
01421 }
01422
01423
01424
01425
01426 float AssociationWidget::totalLength() {
01427 uint size = m_LinePath.count();
01428 float total_length = 0;
01429
01430 for(uint i = 0; i < size - 1; i++) {
01431 QPoint pi = m_LinePath.getPoint( i );
01432 QPoint pj = m_LinePath.getPoint( i+1 );
01433 int xi = pi.y();
01434 int xj = pj.y();
01435 int yi = pi.x();
01436 int yj = pj.x();
01437 total_length += sqrt( double(((xj - xi)*(xj - xi)) + ((yj - yi)*(yj - yi))) );
01438 }
01439
01440 return total_length;
01441 }
01442
01443
01448 QPoint AssociationWidget::calculatePointAtDistance(const QPoint &P1, const QPoint &P2, float Distance) {
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504 int x1 = P1.y();
01505 int y1 = P1.x();
01506 int x2 = P2.y();
01507 int y2 = P2.x();
01508
01509 if(x2 == x1) {
01510 return QPoint(x1, y1 + (int)Distance);
01511 }
01512 float slope = ((float)y2 - (float)y1) / ((float)x2 - (float)x1);
01513 float b = (y1 - slope*x1);
01514 float A = (slope * slope) + 1;
01515 float B = (2*slope*b) - (2*x1) - (2*slope*y1);
01516 float C = (b*b) - (Distance*Distance) + (x1*x1) + (y1*y1) - (2*b*y1);
01517 float t = B*B - 4*A*C;
01518
01519 if(t < 0) {
01520 return QPoint(-1, -1);
01521 }
01522 float sol_1 = ((-1* B) + sqrt(t) ) / (2*A);
01523 float sol_2 = ((-1*B) - sqrt(t) ) / (2*A);
01524
01525 if(sol_1 < 0.0 && sol_2 < 0.0) {
01526 return QPoint(-1, -1);
01527 }
01528 QPoint sol1Point((int)(slope*sol_1 + b), (int)(sol_1));
01529 QPoint sol2Point((int)(slope*sol_2 + b), (int)(sol_2));
01530 if(sol_1 < 0 && sol_2 >=0) {
01531 if(x2 > x1) {
01532 if(x1 <= sol_2 && sol_2 <= x2)
01533 return sol2Point;
01534 } else {
01535 if(x2 <= sol_2 && sol_2 <= x1)
01536 return sol2Point;
01537 }
01538 } else if(sol_1 >= 0 && sol_2 < 0) {
01539 if(x2 > x1) {
01540 if(x1 <= sol_1 && sol_1 <= x2)
01541 return sol1Point;
01542 } else {
01543 if(x2 <= sol_1 && sol_1 <= x1)
01544 return sol1Point;
01545 }
01546 } else {
01547 if(x2 > x1) {
01548 if(x1 <= sol_1 && sol_1 <= x2)
01549 return sol1Point;
01550 if(x1 <= sol_2 && sol_2 <= x2)
01551 return sol2Point;
01552 } else {
01553 if(x2 <= sol_1 && sol_1 <= x1)
01554 return sol1Point;
01555 if(x2 <= sol_2 && sol_2 <= x1)
01556 return sol2Point;
01557 }
01558 }
01559 return QPoint(-1, -1);
01560 }
01561
01566 QPoint AssociationWidget::calculatePointAtDistanceOnPerpendicular(const QPoint &P1, const QPoint &P2, float Distance) {
01567
01568
01569
01570
01571
01572
01573
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631 if (P1.x() == P2.x()) {
01632 return QPoint((int)(P2.x() + Distance), P2.y());
01633 }
01634 const int x1 = P1.y();
01635 const int y1 = P1.x();
01636 const int x2 = P2.y();
01637 const int y2 = P2.x();
01638
01639 float slope = ((float)x1 - (float)x2) / ((float)y2 - (float)y1);
01640 float b = (y2 - slope*x2);
01641 float A = (slope * slope) + 1;
01642 float B = (2*slope*b) - (2*x2) - (2*slope*y2);
01643 float C = (b*b) - (Distance*Distance) + (x2*x2) + (y2*y2) - (2*b*y2);
01644 float t = B*B - 4*A*C;
01645 if (t < 0) {
01646 return QPoint(-1, -1);
01647 }
01648 float sol_1 = ((-1* B) + sqrt(t) ) / (2*A);
01649
01650 float sol_2 = ((-1*B) - sqrt(t) ) / (2*A);
01651
01652 if(sol_1 < 0 && sol_2 < 0) {
01653 return QPoint(-1, -1);
01654 }
01655 QPoint sol1Point((int)(slope*sol_1 + b), (int)sol_1);
01656 QPoint sol2Point((int)(slope*sol_2 + b), (int)sol_2);
01657 if(sol_1 < 0 && sol_2 >=0) {
01658 return sol2Point;
01659 } else if(sol_1 >= 0 && sol_2 < 0) {
01660 return sol1Point;
01661 } else {
01662 if(slope >= 0) {
01663 if(sol_1 <= sol_2)
01664 return sol2Point;
01665 else
01666 return sol1Point;
01667 } else {
01668 if(sol_1 <= sol_2)
01669 return sol1Point;
01670 else
01671 return sol2Point;
01672 }
01673
01674 }
01675 return QPoint(-1, -1);
01676 }
01677
01681 float AssociationWidget::perpendicularProjection(QPoint P1, QPoint P2, QPoint P3,
01682 QPoint& ResultingPoint) {
01683
01684
01685
01686
01687 float slope2 = 0;
01688 float slope1 = 0;
01689 float sx = 0, sy = 0;
01690 int y2 = P2.x();
01691 int y1 = P1.x();
01692 int x2 = P2.y();
01693 int x1 = P1.y();
01694 int y3 = P3.x();
01695 int x3 = P3.y();
01696 float distance = 0;
01697 float b1 = 0;
01698
01699 float b2 = 0;
01700
01701 if(x2 == x1) {
01702 sx = x2;
01703 sy = y3;
01704 } else if(y2 == y1) {
01705 sy = y2;
01706 sx = x3;
01707 } else {
01708 slope1 = (y2 - y1)/ (x2 - x1);
01709 slope2 = (x1 - x2)/ (y2 - y1);
01710 b1 = y2 - (slope1 * x2);
01711 b2 = y3 - (slope2 * x3);
01712 sx = (b2 - b1) / (slope1 - slope2);
01713 sy = slope1*sx + b1;
01714 }
01715 distance = (int)( sqrt( ((x3 - sx)*(x3 - sx)) + ((y3 - sy)*(y3 - sy)) ) );
01716
01717 ResultingPoint.setX( (int)sy );
01718 ResultingPoint.setY( (int)sx );
01719
01720 return distance;
01721 }
01722
01723 QPoint AssociationWidget::calculateTextPosition(Text_Role role) {
01724 const int SPACE = 2;
01725 QPoint p(-1, -1), q(-1, -1);
01726
01727
01728
01729 bool is_top_or_bottom(false);
01730 UMLWidget *pWidget(0);
01731
01732 if (role == tr_MultiA || role == tr_ChangeA || role == tr_RoleAName) {
01733 p = m_LinePath.getPoint( 0 );
01734 q = m_LinePath.getPoint( 1 );
01735 pWidget = m_role[A].m_pWidget;
01736 } else if (role == tr_MultiB || role == tr_ChangeB || role == tr_RoleBName) {
01737 const uint lastSegment = m_LinePath.count() - 1;
01738 p = m_LinePath.getPoint(lastSegment);
01739 q = m_LinePath.getPoint(lastSegment - 1);
01740 pWidget = m_role[B].m_pWidget;
01741 } else if (role != tr_Name) {
01742 kError() << "AssociationWidget::calculateTextPosition called with unsupported Text_Role "
01743 << role << endl;
01744 return QPoint(-1, -1);
01745 }
01746
01747 if ( pWidget && ( pWidget->getY() == p.y() || pWidget->getY() + pWidget->height() == p.y() ))
01748 is_top_or_bottom = true;
01749
01750 FloatingTextWidget *text = getTextWidgetByRole(role);
01751 int textW = 0, textH = 0;
01752 if (text) {
01753 textW = text->width();
01754 textH = text->height();
01755 }
01756
01757 int x = 0, y = 0;
01758
01759 if (role == tr_MultiA || role == tr_MultiB) {
01760 const bool isHorizontal = (p.y() == q.y());
01761 const int atBottom = p.y() + SPACE;
01762 const int atTop = p.y() - SPACE - textH;
01763 const int atLeft = p.x() - SPACE - textW;
01764 const int atRight = p.x() + SPACE;
01765 y = (p.y() > q.y()) == isHorizontal ? atBottom : atTop;
01766 x = (p.x() < q.x()) == isHorizontal ? atRight : atLeft;
01767
01768 } else if (role == tr_ChangeA || role == tr_ChangeB) {
01769
01770 if( p.y() > q.y() )
01771 y = p.y() - SPACE - (textH * 2);
01772 else
01773 y = p.y() + SPACE + textH;
01774
01775 if( p.x() < q.x() )
01776 x = p.x() + SPACE;
01777 else
01778 x = p.x() - SPACE - textW;
01779
01780 } else if (role == tr_RoleAName || role == tr_RoleBName) {
01781
01782 if( p.y() > q.y() )
01783 y = p.y() - SPACE - textH;
01784 else
01785 y = p.y() + SPACE;
01786
01787 if( p.x() < q.x() )
01788 x = p.x() + SPACE;
01789 else
01790 x = p.x() - SPACE - textW;
01791
01792 } else if (role == tr_Name) {
01793
01794 calculateNameTextSegment();
01795 x = (int)( ( m_LinePath.getPoint(m_unNameLineSegment).x() +
01796 m_LinePath.getPoint(m_unNameLineSegment + 1).x() ) / 2 );
01797
01798 y = (int)( ( m_LinePath.getPoint(m_unNameLineSegment).y() +
01799 m_LinePath.getPoint(m_unNameLineSegment + 1).y() ) / 2 );
01800 }
01801
01802 if (text) {
01803 constrainTextPos(x, y, textW, textH, role);
01804 }
01805 p = QPoint( x, y );
01806 return p;
01807 }
01808
01809 QPoint AssociationWidget::midPoint(QPoint p0, QPoint p1) {
01810 QPoint midP;
01811 if (p0.x() < p1.x())
01812 midP.setX(p0.x() + (p1.x() - p0.x()) / 2);
01813 else
01814 midP.setX(p1.x() + (p0.x() - p1.x()) / 2);
01815 if (p0.y() < p1.y())
01816 midP.setY(p0.y() + (p1.y() - p0.y()) / 2);
01817 else
01818 midP.setY(p1.y() + (p0.y() - p1.y()) / 2);
01819 return midP;
01820 }
01821
01822 void AssociationWidget::constrainTextPos(int &textX, int &textY,
01823 int textWidth, int textHeight,
01824 Uml::Text_Role tr) {
01825 const int textCenterX = textX + textWidth / 2;
01826 const int textCenterY = textY + textHeight / 2;
01827 const uint lastSegment = m_LinePath.count() - 1;
01828 QPoint p0, p1;
01829 switch (tr) {
01830 case tr_RoleAName:
01831 case tr_MultiA:
01832 case tr_ChangeA:
01833 p0 = m_LinePath.getPoint(0);
01834 p1 = m_LinePath.getPoint(1);
01835
01836
01837
01838
01839 if (lastSegment == 1)
01840 p1 = midPoint(p0, p1);
01841 break;
01842 case tr_RoleBName:
01843 case tr_MultiB:
01844 case tr_ChangeB:
01845 p0 = m_LinePath.getPoint(lastSegment - 1);
01846 p1 = m_LinePath.getPoint(lastSegment);
01847 if (lastSegment == 1)
01848 p0 = midPoint(p0, p1);
01849 break;
01850 case tr_Name:
01851 case tr_Coll_Message:
01852 case tr_State:
01853
01854
01855 {
01856 int minDistSquare = 100000;
01857 int lpIndex = 0;
01858 for (uint i = 0; i < lastSegment; i++) {
01859 p0 = m_LinePath.getPoint(i);
01860 p1 = m_LinePath.getPoint(i + 1);
01861 QPoint midP = midPoint(p0, p1);
01862 const int deltaX = textCenterX - midP.x();
01863 const int deltaY = textCenterY - midP.y();
01864 const int cSquare = deltaX * deltaX + deltaY * deltaY;
01865 if (cSquare < minDistSquare) {
01866 minDistSquare = cSquare;
01867 lpIndex = i;
01868 }
01869 }
01870 p0 = m_LinePath.getPoint(lpIndex);
01871 p1 = m_LinePath.getPoint(lpIndex + 1);
01872 }
01873 break;
01874 default:
01875 kError() << "AssociationWidget::constrainTextPos(): unexpected Text_Role "
01876 << tr << endl;
01877 return;
01878 break;
01879 }
01880
01881
01882
01883
01884
01885
01886 p0 = swapXY(p0);
01887 p1 = swapXY(p1);
01888 QPoint midP = midPoint(p0, p1);
01889
01890
01891 const int x0 = p0.x();
01892 const int y0 = p0.y();
01893 const int x1 = p1.x();
01894 const int y1 = p1.y();
01895 double r = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)) / 2;
01896 if (textWidth > r)
01897 r = textWidth;
01898
01899 const QPoint origTextCenter(textCenterY, textCenterX);
01900 const int relX = abs(origTextCenter.x() - midP.x());
01901 const int relY = abs(origTextCenter.y() - midP.y());
01902 const double negativeWhenInsideCircle = relX * relX + relY * relY - r * r;
01903 if (negativeWhenInsideCircle <= 0.0) {
01904 return;
01905 }
01906
01907
01908
01909
01910
01911
01912
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922
01923
01924
01925
01926
01927
01928
01929
01930
01931
01932
01933
01934
01935
01936
01937
01938 if (relX == 0) {
01939 if (origTextCenter.y() > midP.y())
01940 textX = midP.y() + (int)r;
01941 else
01942 textX = midP.y() - (int)r;
01943 textX -= textWidth / 2;
01944 return;
01945 }
01946 const double a = (double)relY / (double)relX;
01947 const double x = sqrt(r*r / (a*a + 1));
01948 const double y = a * x;
01949 if (origTextCenter.x() > midP.x())
01950 textY = midP.x() + (int)x;
01951 else
01952 textY = midP.x() - (int)x;
01953 textY -= textHeight / 2;
01954 if (origTextCenter.y() > midP.y())
01955 textX = midP.y() + (int)y;
01956 else
01957 textX = midP.y() - (int)y;
01958 textX -= textWidth / 2;
01959 }
01960
01961 void AssociationWidget::calculateNameTextSegment() {
01962 if(!m_pName) {
01963 return;
01964 }
01965
01966
01967
01968
01969 int xt = m_pName -> getX();
01970 int yt = m_pName -> getY();
01971 xt += m_pName -> getWidth() / 2;
01972 yt += m_pName -> getHeight() / 2;
01973 uint size = m_LinePath.count();
01974
01975 float total_length = 0;
01976 float smallest_length = 0;
01977 for(uint i = 0; i < size - 1; i++) {
01978 QPoint pi = m_LinePath.getPoint( i );
01979 QPoint pj = m_LinePath.getPoint( i+1 );
01980 int xtiDiff = xt - pi.x();
01981 int xtjDiff = xt - pj.x();
01982 int ytiDiff = yt - pi.y();
01983 int ytjDiff = yt - pj.y();
01984 total_length = sqrt( double(xtiDiff * xtiDiff + ytiDiff * ytiDiff) )
01985 + sqrt( double(xtjDiff * xtjDiff + ytjDiff * ytjDiff) );
01986
01987 if( total_length < smallest_length || i == 0) {
01988 smallest_length = total_length;
01989 m_unNameLineSegment = i;
01990 }
01991 }
01992 }
01993
01994 void AssociationWidget::setTextPosition(Text_Role role) {
01995 bool startMove = false;
01996 if( m_role[A].m_pMulti && m_role[A].m_pMulti->getStartMove() )
01997 startMove = true;
01998 else if( m_role[B].m_pMulti && m_role[B].m_pMulti->getStartMove() )
01999 startMove = true;
02000 else if( m_role[A].m_pChangeWidget && m_role[A].m_pChangeWidget->getStartMove() )
02001 startMove = true;
02002 else if( m_role[B].m_pChangeWidget && m_role[B].m_pChangeWidget->getStartMove() )
02003 startMove = true;
02004 else if( m_role[A].m_pRole && m_role[A].m_pRole->getStartMove() )
02005 startMove = true;
02006 else if( m_role[B].m_pRole && m_role[B].m_pRole->getStartMove() )
02007 startMove = true;
02008 else if( m_pName && m_pName->getStartMove() )
02009 startMove = true;
02010
02011 if (startMove) {
02012 return;
02013 }
02014 FloatingTextWidget *ft = getTextWidgetByRole(role);
02015 if (ft == NULL)
02016 return;
02017 QPoint pos = calculateTextPosition(role);
02018 int x = pos.x();
02019 int y = pos.y();
02020 if ( (x < 0 || x > FloatingTextWidget::restrictPositionMax) ||
02021 (y < 0 || y > FloatingTextWidget::restrictPositionMax) ) {
02022 kDebug() << "AssociationWidget::setTextPosition( " << x << " , " << y << " ) "
02023 << "- was blocked because at least one value is out of bounds: ["
02024 << "0 ... " << FloatingTextWidget::restrictPositionMax << "]"
02025 << endl;
02026 return;
02027 }
02028 ft->setX( x );
02029 ft->setY( y );
02030 }
02031
02032 void AssociationWidget::setTextPositionRelatively(Text_Role role, const QPoint &oldPosition) {
02033 bool startMove = false;
02034 if( m_role[A].m_pMulti && m_role[A].m_pMulti->getStartMove() )
02035 startMove = true;
02036 else if( m_role[B].m_pMulti && m_role[B].m_pMulti->getStartMove() )
02037 startMove = true;
02038 else if( m_role[A].m_pChangeWidget && m_role[A].m_pChangeWidget->getStartMove() )
02039 startMove = true;
02040 else if( m_role[B].m_pChangeWidget && m_role[B].m_pChangeWidget->getStartMove() )
02041 startMove = true;
02042 else if( m_role[A].m_pRole && m_role[A].m_pRole->getStartMove() )
02043 startMove = true;
02044 else if( m_role[B].m_pRole && m_role[B].m_pRole->getStartMove() )
02045 startMove = true;
02046 else if( m_pName && m_pName->getStartMove() )
02047 startMove = true;
02048
02049 if (startMove) {
02050 return;
02051 }
02052 FloatingTextWidget *ft = getTextWidgetByRole(role);
02053 if (ft == NULL)
02054 return;
02055 int ftX = ft->getX();
02056 int ftY = ft->getY();
02057 if ( (ftX < 0 || ftX > FloatingTextWidget::restrictPositionMax) ||
02058 (ftY < 0 || ftY > FloatingTextWidget::restrictPositionMax) ) {
02059 kDebug() << "AssociationWidget::setTextPositionRelatively: "
02060 << "blocked because the FloatingTextWidget original position ("
02061 << ftX << "," << ftY << " is out of bounds: [0 ... "
02062 << FloatingTextWidget::restrictPositionMax << "]" << endl;
02063 return;
02064 }
02065 QPoint pos = calculateTextPosition(role);
02066 int relX = pos.x() - oldPosition.x();
02067 int relY = pos.y() - oldPosition.y();
02068 int ftNewX = ftX + relX;
02069 int ftNewY = ftY + relY;
02070 if ( (ftNewX < 0 || ftNewX > FloatingTextWidget::restrictPositionMax) ||
02071 (ftNewY < 0 || ftNewY > FloatingTextWidget::restrictPositionMax) ) {
02072 kDebug() << "AssociationWidget::setTextPositionRelatively: "
02073 << "blocked because the FloatingTextWidget new position ("
02074 << ftNewX << "," << ftNewY << " is out of bounds: [0 ... "
02075 << FloatingTextWidget::restrictPositionMax << "]" << endl;
02076 return;
02077 }
02078 bool oldIgnoreSnapToGrid = ft->getIgnoreSnapToGrid();
02079 ft->setIgnoreSnapToGrid( true );
02080 ft->setX( ftNewX );
02081 ft->setY( ftNewY );
02082 ft->setIgnoreSnapToGrid( oldIgnoreSnapToGrid );
02083 }
02084
02085 void AssociationWidget::removeAssocClassLine() {
02086 selectAssocClassLine(false);
02087 if (m_pAssocClassLine) {
02088 delete m_pAssocClassLine;
02089 m_pAssocClassLine = NULL;
02090 }
02091 if (m_pAssocClassWidget) {
02092 m_pAssocClassWidget->setClassAssocWidget(NULL);
02093 m_pAssocClassWidget = NULL;
02094 }
02095 }
02096
02097 void AssociationWidget::createAssocClassLine() {
02098 if (m_pAssocClassLine == NULL)
02099 m_pAssocClassLine = new QCanvasLine(m_pView->canvas());
02100 computeAssocClassLine();
02101 QPen pen(getLineColor(), getLineWidth(), Qt::DashLine);
02102 m_pAssocClassLine->setPen(pen);
02103 m_pAssocClassLine->setVisible(true);
02104 }
02105
02106 void AssociationWidget::createAssocClassLine(ClassifierWidget* classifier,
02107 int linePathSegmentIndex) {
02108 m_nLinePathSegmentIndex = linePathSegmentIndex;
02109
02110 if (m_nLinePathSegmentIndex < 0) {
02111 return;
02112 }
02113
02114 m_pAssocClassWidget = classifier;
02115 m_pAssocClassWidget->setClassAssocWidget(this);
02116
02117 createAssocClassLine();
02118 }
02119
02120 void AssociationWidget::computeAssocClassLine() {
02121 if (m_pAssocClassWidget == NULL || m_pAssocClassLine == NULL)
02122 return;
02123 if (m_nLinePathSegmentIndex < 0) {
02124 kError() << "AssociationWidget::computeAssocClassLine: "
02125 << "m_nLinePathSegmentIndex is not set" << endl;
02126 return;
02127 }
02128 QPoint segStart = m_LinePath.getPoint(m_nLinePathSegmentIndex);
02129 QPoint segEnd = m_LinePath.getPoint(m_nLinePathSegmentIndex + 1);
02130 const int midSegX = segStart.x() + (segEnd.x() - segStart.x()) / 2;
02131 const int midSegY = segStart.y() + (segEnd.y() - segStart.y()) / 2;
02132
02133 QPoint segmentMidPoint(midSegX, midSegY);
02134 QRect classRectangle = m_pAssocClassWidget->rect();
02135 QPoint cwEdgePoint = findIntercept(classRectangle, segmentMidPoint);
02136 int acwMinX = cwEdgePoint.x();
02137 int acwMinY = cwEdgePoint.y();
02138
02139 m_pAssocClassLine->setPoints(midSegX, midSegY, acwMinX, acwMinY);
02140 }
02141
02142 void AssociationWidget::selectAssocClassLine(bool sel ) {
02143 if (!sel) {
02144 if (m_pAssocClassLineSel0) {
02145 delete m_pAssocClassLineSel0;
02146 m_pAssocClassLineSel0 = NULL;
02147 }
02148 if (m_pAssocClassLineSel1) {
02149 delete m_pAssocClassLineSel1;
02150 m_pAssocClassLineSel1 = NULL;
02151 }
02152 return;
02153 }
02154 if (m_pAssocClassLine == NULL) {
02155 kError() << "AssociationWidget::selectAssocClassLine: "
02156 << "cannot select because m_pAssocClassLine is NULL"
02157 << endl;
02158 return;
02159 }
02160 if (m_pAssocClassLineSel0)
02161 delete m_pAssocClassLineSel0;
02162 m_pAssocClassLineSel0 = Widget_Utils::decoratePoint(m_pAssocClassLine->startPoint());
02163 if (m_pAssocClassLineSel1)
02164 delete m_pAssocClassLineSel1;
02165 m_pAssocClassLineSel1 = Widget_Utils::decoratePoint(m_pAssocClassLine->endPoint());
02166 }
02167
02168 void AssociationWidget::mousePressEvent(QMouseEvent * me) {
02169 m_nMovingPoint = -1;
02170
02171 if(me -> button() != Qt::RightButton && me->button() != Qt::LeftButton)
02172 return;
02173 QPoint mep = me->pos();
02174
02175 if (onAssocClassLine(mep)) {
02176 m_bSelected = true;
02177 selectAssocClassLine();
02178 return;
02179 }
02180
02181
02182 checkPoints(mep);
02183 if( me -> state() != Qt::ShiftButton )
02184 m_pView -> clearSelected();
02185 setSelected( !m_bSelected );
02186 }
02187
02188 void AssociationWidget::mouseReleaseEvent(QMouseEvent * me) {
02189 if(me -> button() != Qt::RightButton && me->button() != Qt::LeftButton) {
02190 setSelected( false );
02191 return;
02192 }
02193
02194
02195
02196
02198 if (m_nMovingPoint > 0 && m_nMovingPoint < m_LinePath.count() - 1)
02199 {
02200 QPoint m = m_LinePath.getPoint(m_nMovingPoint);
02201 QPoint b = m_LinePath.getPoint(m_nMovingPoint - 1);
02202 QPoint a = m_LinePath.getPoint(m_nMovingPoint + 1);
02203 if ( (b.x() == m.x() && a.x() == m.x()) ||
02204 (b.y() == m.y() && a.y() == m.y()) )
02205 m_LinePath.removePoint(m_nMovingPoint, m, POINT_DELTA);
02206 }
02207 m_nMovingPoint = -1;
02208 const QPoint p = me->pos();
02209
02210 if (me->button() != Qt::RightButton) {
02211 return;
02212 }
02213
02214
02215
02216
02217
02218 ListPopupMenu::Menu_Type menuType = ListPopupMenu::mt_Undefined;
02219 const int DISTANCE = 40;
02220 const QPoint lpStart = m_LinePath.getPoint(0);
02221 const QPoint lpEnd = m_LinePath.getPoint(m_LinePath.count() - 1);
02222 const int startXDiff = lpStart.x() - p.x();
02223 const int startYDiff = lpStart.y() - p.y();
02224 const int endXDiff = lpEnd.x() - p.x();
02225 const int endYDiff = lpEnd.y() - p.y();
02226 const float lengthMAP = sqrt( double(startXDiff * startXDiff + startYDiff * startYDiff) );
02227 const float lengthMBP = sqrt( double(endXDiff * endXDiff + endYDiff * endYDiff) );
02228 const Association_Type type = getAssocType();
02229
02230 if( AssocRules::allowMultiplicity( type, getWidget(A) -> getBaseType() ) ) {
02231 if(lengthMAP < DISTANCE)
02232 menuType = ListPopupMenu::mt_MultiA;
02233 else if(lengthMBP < DISTANCE)
02234 menuType = ListPopupMenu::mt_MultiB;
02235 }
02236 if( menuType == ListPopupMenu::mt_Undefined ) {
02237 if (type == at_Anchor || onAssocClassLine(p))
02238 menuType = ListPopupMenu::mt_Anchor;
02239 else if (isCollaboration())
02240 menuType = ListPopupMenu::mt_Collaboration_Message;
02241 else if( AssocRules::allowRole( type ) )
02242 menuType = ListPopupMenu::mt_FullAssociation;
02243 else
02244 menuType = ListPopupMenu::mt_Association_Selected;
02245 }
02246 m_pMenu = new ListPopupMenu(m_pView, menuType);
02247 m_pMenu->popup(me -> globalPos());
02248 connect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotMenuSelection(int)));
02249 setSelected();
02250 }
02251
02252 bool AssociationWidget::showDialog() {
02253 AssocPropDlg dlg(static_cast<QWidget*>(m_pView), this );
02254 if (! dlg.exec())
02255 return false;
02256 QString name = getName();
02257 QString doc = getDoc();
02258 QString roleADoc = getRoleDoc(A), roleBDoc = getRoleDoc(B);
02259 QString rnA = getRoleName(A), rnB = getRoleName(B);
02260 QString ma = getMulti(A), mb = getMulti(B);
02261 Uml::Visibility vA = getVisibility(A), vB = getVisibility(B);
02262 Changeability_Type cA = getChangeability(A), cB = getChangeability(B);
02263
02264 setName(name);
02265 setRoleName(rnA, A);
02266 setRoleName(rnB, B);
02267 setDoc(doc);
02268 setRoleDoc(roleADoc, A);
02269 setRoleDoc(roleBDoc, B);
02270 setMulti(ma, A);
02271 setMulti(mb, B);
02272 setVisibility(vA, A);
02273 setVisibility(vB, B);
02274 setChangeability(cA, A);
02275 setChangeability(cB, B);
02276 m_pView -> showDocumentation( this, true );
02277 return true;
02278 }
02279
02280 void AssociationWidget::slotMenuSelection(int sel) {
02281 QString oldText, newText;
02282 QFont font;
02283 QRegExpValidator v(QRegExp(".*"), 0);
02284 Uml::Association_Type atype = getAssocType();
02285 Uml::Role_Type r = Uml::B;
02286
02287
02288
02289 if (isCollaboration() && sel != ListPopupMenu::mt_Delete) {
02290 m_pName->slotMenuSelection(sel);
02291 return;
02292 }
02293
02294 switch(sel) {
02295 case ListPopupMenu::mt_Properties:
02296 if(atype == at_Seq_Message || atype == at_Seq_Message_Self) {
02297
02298
02299
02300
02301 kDebug() << "AssociationWidget::slotMenuSelection(mt_Properties): "
02302 << "assoctype is " << atype << endl;
02303 } else {
02304 m_pView -> updateDocumentation( false );
02305 showDialog();
02306 }
02307 break;
02308
02309 case ListPopupMenu::mt_Delete:
02310 if (m_pAssocClassLineSel0)
02311 removeAssocClassLine();
02312 else
02313 m_pView->removeAssocInViewAndDoc(this);
02314 break;
02315
02316 case ListPopupMenu::mt_Rename_MultiA:
02317 r = Uml::A;
02318 case ListPopupMenu::mt_Rename_MultiB:
02319 if (m_role[r].m_pMulti)
02320 oldText = m_role[r].m_pMulti->getText();
02321 else
02322 oldText = "";
02323 newText = KInputDialog::getText(i18n("Multiplicity"),
02324 i18n("Enter multiplicity:"),
02325 oldText, NULL, m_pView, NULL, &v);
02326 if (newText != oldText) {
02327 if (FloatingTextWidget::isTextValid(newText)) {
02328 setMulti(newText, r);
02329 } else {
02330 m_pView->removeWidget(m_role[r].m_pMulti);
02331 m_role[r].m_pMulti = NULL;
02332 }
02333 }
02334 break;
02335
02336 case ListPopupMenu::mt_Rename_Name:
02337 if(m_pName)
02338 oldText = m_pName->getText();
02339 else
02340 oldText = "";
02341 newText = KInputDialog::getText(i18n("Association Name"),
02342 i18n("Enter association name:"),
02343 oldText, NULL, m_pView, NULL, &v);
02344 if (newText != oldText) {
02345 if (FloatingTextWidget::isTextValid(newText)) {
02346 setName(newText);
02347 } else {
02348 m_pView->removeWidget(m_pName);
02349 m_pName = NULL;
02350 }
02351 }
02352 break;
02353
02354 case ListPopupMenu::mt_Rename_RoleAName:
02355 r = Uml::A;
02356 case ListPopupMenu::mt_Rename_RoleBName:
02357 if (m_role[r].m_pRole)
02358 oldText = m_role[r].m_pRole->getText();
02359 else
02360 oldText = "";
02361 newText = KInputDialog::getText(i18n("Role Name"),
02362 i18n("Enter role name:"),
02363 oldText, NULL, m_pView, NULL, &v);
02364 if (newText != oldText) {
02365 if (FloatingTextWidget::isTextValid(newText)) {
02366 setRoleName(newText, r);
02367 } else {
02368 m_pView->removeWidget(m_role[r].m_pRole);
02369 m_role[r].m_pRole = NULL;
02370 }
02371 }
02372 break;
02373
02374 case ListPopupMenu::mt_Change_Font:
02375 font = getFont();
02376 if( KFontDialog::getFont( font, false, m_pView ) )
02377 lwSetFont(font);
02378 break;
02379
02380 case ListPopupMenu::mt_Change_Font_Selection:
02381 font = getFont();
02382 if( KFontDialog::getFont( font, false, m_pView ) ) {
02383 m_pView -> selectionSetFont( font );
02384 m_umldoc->setModified(true);
02385 }
02386 break;
02387
02388 case ListPopupMenu::mt_Line_Color:
02389 case ListPopupMenu::mt_Line_Color_Selection:
02390 {
02391 QColor newColour;
02392 if( KColorDialog::getColor(newColour) ) {
02393 m_pView->selectionSetLineColor(newColour);
02394 m_umldoc->setModified(true);
02395 }
02396 }
02397 break;
02398
02399 case ListPopupMenu::mt_Cut:
02400 m_pView->setStartedCut();
02401 UMLApp::app()->slotEditCut();
02402 break;
02403
02404 case ListPopupMenu::mt_Copy:
02405 UMLApp::app()->slotEditCopy();
02406 break;
02407
02408 case ListPopupMenu::mt_Paste:
02409 UMLApp::app()->slotEditPaste();
02410 break;
02411
02412 case ListPopupMenu::mt_Reset_Label_Positions:
02413 resetTextPositions();
02414 break;
02415 }
02416 }
02417
02418
02419 void AssociationWidget::lwSetFont (QFont font) {
02420 if( m_pName) {
02421 m_pName->setFont( font );
02422 }
02423 if( m_role[A].m_pRole ) {
02424 m_role[A].m_pRole->setFont( font );
02425 }
02426 if( m_role[B].m_pRole ) {
02427 m_role[B].m_pRole->setFont( font );
02428 }
02429 if( m_role[A].m_pMulti ) {
02430 m_role[A].m_pMulti->setFont( font );
02431 }
02432 if( m_role[B].m_pMulti ) {
02433 m_role[B].m_pMulti->setFont( font );
02434 }
02435 if( m_role[A].m_pChangeWidget)
02436 m_role[A].m_pChangeWidget->setFont( font );
02437 if( m_role[B].m_pChangeWidget)
02438 m_role[B].m_pChangeWidget->setFont( font );
02439 }
02440
02441
02442 QFont AssociationWidget::getFont() const {
02443 QFont font;
02444
02445 if( m_role[A].m_pRole )
02446 font = m_role[A].m_pRole -> getFont( );
02447 else if( m_role[B].m_pRole)
02448 font = m_role[B].m_pRole -> getFont( );
02449 else if( m_role[A].m_pMulti )
02450 font = m_role[A].m_pMulti -> getFont( );
02451 else if( m_role[B].m_pMulti )
02452 font = m_role[B].m_pMulti -> getFont( );
02453 else if( m_role[A].m_pChangeWidget)
02454 font = m_role[A].m_pChangeWidget-> getFont( );
02455 else if( m_role[B].m_pChangeWidget)
02456 font = m_role[B].m_pChangeWidget-> getFont( );
02457 else if( m_pName)
02458 font = m_pName-> getFont( );
02459 else
02460 font = m_role[A].m_pWidget -> getFont();
02461
02462 return font;
02463 }
02464
02465 void AssociationWidget::setLineColor(const QColor &colour) {
02466 WidgetBase::setLineColor(colour);
02467 m_LinePath.setLineColor(colour);
02468 }
02469
02470 void AssociationWidget::setLineWidth(uint width) {
02471 WidgetBase::setLineWidth(width);
02472 m_LinePath.setLineWidth(width);
02473 }
02474
02475 void AssociationWidget::checkPoints(const QPoint &p) {
02476 m_nMovingPoint = -1;
02477
02478 int size = m_LinePath.count();
02479 if( size <= 2 )
02480 return;
02481
02482 QPoint tempPoint;
02483 int x, y;
02484 const int BOUNDARY = 4;
02485 for(int i=1;i<size-1;i++) {
02486 tempPoint = m_LinePath.getPoint( i );
02487 x = tempPoint.x();
02488 y = tempPoint.y();
02489 if( x - BOUNDARY <= p.x() && x + BOUNDARY >= p.x() &&
02490 y - BOUNDARY <= p.y() && y + BOUNDARY >= p.y() ) {
02491 m_nMovingPoint = i;
02492 break;
02493 }
02494 }
02495 }
02496
02497 void AssociationWidget::mouseMoveEvent(QMouseEvent* me) {
02498 if( me->state() != Qt::LeftButton) {
02499 return;
02500 }
02501
02502
02503 if (m_nMovingPoint == -1)
02504 {
02505
02506 int i = m_LinePath.onLinePath(me->pos());
02507
02508 if (i == -1)
02509 return;
02510 m_LinePath.insertPoint( i + 1, me->pos() );
02511 m_nMovingPoint = i + 1;
02512 }
02513
02514 setSelected();
02515
02516 QPoint p = me->pos();
02517 QPoint oldp = m_LinePath.getPoint(m_nMovingPoint);
02518
02519 if( m_pView -> getSnapToGrid() ) {
02520 int newX = m_pView->snappedX( p.x() );
02521 int newY = m_pView->snappedY( p.y() );
02522 p.setX(newX);
02523 p.setY(newY);
02524 }
02525
02526
02527
02528 UMLWidget *onW = m_pView->getWidgetAt(p);
02529 if (onW && onW->getBaseType() != Uml::wt_Box) {
02530 const int pX = p.x();
02531 const int pY = p.y();
02532 const int wX = onW->getX();
02533 const int wY = onW->getY();
02534 const int wWidth = onW->getWidth();
02535 const int wHeight = onW->getHeight();
02536 if (pX > wX && pX < wX + wWidth) {
02537 const int midX = wX + wWidth / 2;
02538 if (pX <= midX)
02539 p.setX(wX);
02540 else
02541 p.setX(wX + wWidth);
02542 }
02543 if (pY > wY && pY < wY + wHeight) {
02544 const int midY = wY + wHeight / 2;
02545 if (pY <= midY)
02546 p.setY(wY);
02547 else
02548 p.setY(wY + wHeight);
02549 }
02550 }
02551
02552
02553 QMoveEvent m(p, oldp);
02554 moveEvent(&m);
02555 m_pView->resizeCanvasToItems();
02556 }
02557
02558 AssociationWidget::Region AssociationWidget::getWidgetRegion(AssociationWidget * widget) const {
02559 if(widget -> getWidget(A) == m_role[A].m_pWidget)
02560 return m_role[A].m_WidgetRegion;
02561 if(widget -> getWidget(B) == m_role[B].m_pWidget)
02562 return m_role[B].m_WidgetRegion;
02563 return Error;
02564 }
02565
02566 int AssociationWidget::getRegionCount(AssociationWidget::Region region, Role_Type role) {
02567 if(region == Error)
02568 return 0;
02569 int widgetCount = 0;
02570 AssociationWidgetList list = m_pView -> getAssociationList();
02571 AssociationWidgetListIt assoc_it(list);
02572 AssociationWidget* assocwidget = 0;
02573 while((assocwidget = assoc_it.current())) {
02574 ++assoc_it;
02575
02576 if (assocwidget == this)
02577 continue;
02578 const WidgetRole& otherA = assocwidget->m_role[A];
02579 const WidgetRole& otherB = assocwidget->m_role[B];
02580 const UMLWidget *a = otherA.m_pWidget;
02581 const UMLWidget *b = otherB.m_pWidget;
02582
02583
02584
02585
02586
02587
02588 if (m_role[role].m_pWidget == a && region == otherA.m_WidgetRegion)
02589 widgetCount++;
02590 else if (m_role[role].m_pWidget == b && region == otherB.m_WidgetRegion)
02591 widgetCount++;
02592 }
02593 return widgetCount;
02594 }
02595
02596 QPoint AssociationWidget::findIntercept(const QRect &rect, const QPoint &point) {
02597 Region region = findPointRegion(rect, point.x(), point.y());
02598
02599
02600
02601
02602
02603
02604
02605
02606
02607
02608
02609
02610 switch (region) {
02611 case NorthWest:
02612 region = North;
02613 break;
02614 case NorthEast:
02615 region = East;
02616 break;
02617 case SouthEast:
02618 region = South;
02619 break;
02620 case SouthWest:
02621 case Center:
02622 region = West;
02623 break;
02624 default:
02625 break;
02626 }
02627
02628
02629
02630
02631 const int rectHalfWidth = rect.height() / 2;
02632 const int rectHalfHeight = rect.width() / 2;
02633 const int rectMidX = rect.y() + rectHalfWidth;
02634 const int rectMidY = rect.x() + rectHalfHeight;
02635 const int pX = point.y();
02636 const int pY = point.x();
02637 const int dX = rectMidX - pX;
02638 const int dY = rectMidY - pY;
02639 switch (region) {
02640 case West:
02641 region = South;
02642 break;
02643 case North:
02644 region = East;
02645 break;
02646 case East:
02647 region = North;
02648 break;
02649 case South:
02650 region = West;
02651 break;
02652 default:
02653 break;
02654 }
02655
02656
02657 if (region == North || region == South) {
02658 int yoff = rectHalfHeight;
02659 if (region == North)
02660 yoff = -yoff;
02661 if (dX == 0) {
02662 return QPoint(rectMidY + yoff, rectMidX);
02663 }
02664 if (dY == 0) {
02665 kError() << "AssociationWidget::findIntercept usage error: "
02666 << "North/South (dY == 0)" << endl;
02667 return QPoint(0,0);
02668 }
02669 const float m = (float)dY / (float)dX;
02670 const float b = (float)pY - m * pX;
02671 const int inputY = rectMidY + yoff;
02672 const float outputX = ((float)inputY - b) / m;
02673 return QPoint(inputY, (int)outputX);
02674 } else {
02675 int xoff = rectHalfWidth;
02676 if (region == East)
02677 xoff = -xoff;
02678 if (dY == 0)
02679 return QPoint(rectMidY, rectMidX + xoff);
02680 if (dX == 0) {
02681 kError() << "AssociationWidget::findIntercept usage error: "
02682 << "East/West (dX == 0)" << endl;
02683 return QPoint(0,0);
02684 }
02685 const float m = (float)dY / (float)dX;
02686 const float b = (float)pY - m * pX;
02687 const int inputX = rectMidX + xoff;
02688 const float outputY = m * (float)inputX + b;
02689 return QPoint((int)outputY, inputX);
02690 }
02691 }
02692
02693 int AssociationWidget::findInterceptOnEdge(const QRect &rect,
02694 AssociationWidget::Region region,
02695 const QPoint &point)
02696 {
02697
02698
02699
02700
02701 const int rectHalfWidth = rect.height() / 2;
02702 const int rectHalfHeight = rect.width() / 2;
02703 const int rectMidX = rect.y() + rectHalfWidth;
02704 const int rectMidY = rect.x() + rectHalfHeight;
02705 const int dX = rectMidX - point.y();
02706 const int dY = rectMidY - point.x();
02707 switch (region) {
02708 case West:
02709 region = South;
02710 break;
02711 case North:
02712 region = West;
02713 break;
02714 case East:
02715 region = North;
02716 break;
02717 case South:
02718 region = East;
02719 break;
02720 default:
02721 break;
02722 }
02723
02724
02725 if (region == North || region == South) {
02726 if (dX == 0)
02727 return rectMidY;
02728
02729 if (dY == 0) {
02730 kError() << "AssociationWidget::findInterceptOnEdge usage error: "
02731 << "North/South (dY == 0)" << endl;
02732 return -1;
02733 }
02734 const float m = (float)dY / (float)dX;
02735 float relativeX;
02736 if (region == North)
02737 relativeX = (float)rectHalfHeight / m;
02738 else
02739 relativeX = -(float)rectHalfHeight / m;
02740 return (rectMidY + (int)relativeX);
02741
02742 } else {
02743 if (dY == 0)
02744 return rectMidX;
02745
02746 if (dX == 0) {
02747 kError() << "AssociationWidget::findInterceptOnEdge usage error: "
02748 << "East/West (dX == 0)" << endl;
02749 return -1;
02750 }
02751 const float m = (float)dY / (float)dX;
02752 float relativeY = m * (float)rectHalfWidth;
02753 if (region == West)
02754 relativeY = -relativeY;
02755 return (rectMidX + (int)relativeY);
02756
02757 }
02758 }
02759
02760 void AssociationWidget::insertIntoLists(int position, const AssociationWidget* assoc)
02761 {
02762 bool did_insertion = false;
02763 for (int index = 0; index < m_positions_len; index++) {
02764 if (position < m_positions[index]) {
02765 for (int moveback = m_positions_len; moveback > index; moveback--)
02766 m_positions[moveback] = m_positions[moveback - 1];
02767 m_positions[index] = position;
02768 m_ordered.insert(index, assoc);
02769 did_insertion = true;
02770 break;
02771 }
02772 }
02773 if (! did_insertion) {
02774 m_positions[m_positions_len] = position;
02775 m_ordered.append(assoc);
02776 }
02777 m_positions_len++;
02778 }
02779
02780 void AssociationWidget::updateAssociations(int totalCount,
02781 AssociationWidget::Region region,
02782 Role_Type role)
02783 {
02784 if( region == Error )
02785 return;
02786 AssociationWidgetList list = m_pView -> getAssociationList();
02787 AssociationWidgetListIt assoc_it(list);
02788 AssociationWidget* assocwidget = 0;
02789 UMLWidget *ownWidget = m_role[role].m_pWidget;
02790 m_positions_len = 0;
02791 m_ordered.clear();
02792
02793 while ( (assocwidget = assoc_it.current()) ) {
02794 ++assoc_it;
02795 WidgetRole *roleA = &assocwidget->m_role[A];
02796 WidgetRole *roleB = &assocwidget->m_role[B];
02797 UMLWidget *wA = roleA->m_pWidget;
02798 UMLWidget *wB = roleB->m_pWidget;
02799
02800 if (wA == wB)
02801 continue;
02802
02803
02804 bool inWidgetARegion = ( ownWidget == wA &&
02805 region == roleA->m_WidgetRegion );
02806 bool inWidgetBRegion = ( ownWidget == wB &&
02807 region == roleB->m_WidgetRegion);
02808 if ( !inWidgetARegion && !inWidgetBRegion )
02809 continue;
02810
02811 UMLWidget * otherWidget = (inWidgetARegion ? wB : wA);
02812 LinePath *linepath = assocwidget->getLinePath();
02813 QPoint refpoint;
02814 if (assocwidget->linePathStartsAt(otherWidget))
02815 refpoint = linepath->getPoint(linepath->count() - 2);
02816 else
02817 refpoint = linepath->getPoint(1);
02818
02819
02820 bool pointIsAuthoritative = (role == B || linepath->count() > 2);
02821 if (! pointIsAuthoritative) {
02822
02823
02824 refpoint.setX(otherWidget->getX() + otherWidget->getWidth() / 2);
02825 refpoint.setY(otherWidget->getY() + otherWidget->getHeight() / 2);
02826 }
02827 int intercept = findInterceptOnEdge(ownWidget->rect(), region, refpoint);
02828 if (intercept < 0) {
02829 kDebug() << "updateAssociations: error from findInterceptOnEdge for"
02830 << " assocType=" << assocwidget->getAssocType()
02831 << " ownWidget=" << ownWidget->getName()
02832 << " otherWidget=" << otherWidget->getName() << endl;
02833 continue;
02834 }
02835 insertIntoLists(intercept, assocwidget);
02836 }
02837
02838
02839 int index = 1;
02840 for (assocwidget = m_ordered.first(); assocwidget; assocwidget = m_ordered.next()) {
02841 if (ownWidget == assocwidget->getWidget(A)) {
02842 assocwidget->updateRegionLineCount(index++, totalCount, region, A);
02843 } else if (ownWidget == assocwidget->getWidget(B)) {
02844 assocwidget->updateRegionLineCount(index++, totalCount, region, B);
02845 }
02846 }
02847 }
02848
02849 void AssociationWidget::updateRegionLineCount(int index, int totalCount,
02850 AssociationWidget::Region region,
02851 Role_Type role) {
02852 if( region == Error )
02853 return;
02854
02855
02856 if (m_role[A].m_pWidget == m_role[B].m_pWidget &&
02857 m_role[A].m_WidgetRegion == m_role[B].m_WidgetRegion) {
02858 UMLWidget * pWidget = m_role[A].m_pWidget;
02859 int x = pWidget -> getX();
02860 int y = pWidget -> getY();
02861 int wh = pWidget -> height();
02862 int ww = pWidget -> width();
02863 int size = m_LinePath.count();
02864
02865 switch( m_role[A].m_WidgetRegion ) {
02866 case North:
02867 m_LinePath.setPoint( 0, QPoint( x + ( ww / 4 ), y ) );
02868 m_LinePath.setPoint( size - 1, QPoint(x + ( ww * 3 / 4 ), y ) );
02869 break;
02870
02871 case South:
02872 m_LinePath.setPoint( 0, QPoint( x + ( ww / 4 ), y + wh ) );
02873 m_LinePath.setPoint( size - 1, QPoint( x + ( ww * 3 / 4 ), y + wh ) );
02874 break;
02875
02876 case East:
02877 m_LinePath.setPoint( 0, QPoint( x + ww, y + ( wh / 4 ) ) );
02878 m_LinePath.setPoint( size - 1, QPoint( x + ww, y + ( wh * 3 / 4 ) ) );
02879 break;
02880
02881 case West:
02882 m_LinePath.setPoint( 0, QPoint( x, y + ( wh / 4 ) ) );
02883 m_LinePath.setPoint( size - 1, QPoint( x, y + ( wh * 3 / 4 ) ) );
02884 break;
02885 default:
02886 break;
02887 }
02888 m_role[A].m_OldCorner.setX( x );
02889 m_role[A].m_OldCorner.setY( y );
02890 m_role[B].m_OldCorner.setX( x );
02891 m_role[B].m_OldCorner.setY( y );
02892
02893 return;
02894 }
02895
02896 WidgetRole& robj = m_role[role];
02897 UMLWidget * pWidget = robj.m_pWidget;
02898
02899 robj.m_nIndex = index;
02900 robj.m_nTotalCount = totalCount;
02901 int x = pWidget->getX();
02902 int y = pWidget->getY();
02903 robj.m_OldCorner.setX(x);
02904 robj.m_OldCorner.setY(y);
02905 int ww = pWidget->getWidth();
02906 int wh = pWidget->getHeight();
02907 const bool angular = Settings::getOptionState().generalState.angularlines;
02908 int ch = 0;
02909 int cw = 0;
02910 if (angular) {
02911 uint nind = (role == A ? 1 : m_LinePath.count() - 2);
02912 QPoint neighbour = m_LinePath.getPoint(nind);
02913 if (neighbour.x() < x)
02914 cw = 0;
02915 else if (neighbour.x() > x + ww)
02916 cw = 0 + ww;
02917 else
02918 cw = neighbour.x() - x;
02919 if (neighbour.y() < y)
02920 ch = 0;
02921 else if (neighbour.y() > y + wh)
02922 ch = 0 + wh;
02923 else
02924 ch = neighbour.y() - y;
02925 } else {
02926 ch = wh * index / totalCount;
02927 cw = ww * index / totalCount;
02928 }
02929
02930 int snapX = m_pView->snappedX(x + cw);
02931 int snapY = m_pView->snappedY(y + ch);
02932
02933 QPoint pt;
02934 if (angular) {
02935 pt = QPoint(snapX, snapY);
02936 } else {
02937 switch(region) {
02938 case West:
02939 pt.setX(x);
02940 pt.setY(snapY);
02941 break;
02942 case North:
02943 pt.setX(snapX);
02944 pt.setY(y);
02945 break;
02946 case East:
02947 pt.setX(x + ww);
02948 pt.setY(snapY);
02949 break;
02950 case South:
02951 pt.setX(snapX);
02952 pt.setY(y + wh);
02953 break;
02954 case Center:
02955 pt.setX(x + ww / 2);
02956 pt.setY(y + wh / 2);
02957 break;
02958 default:
02959 break;
02960 }
02961 }
02962 if (role == A)
02963 m_LinePath.setPoint( 0, pt );
02964 else {
02965 m_LinePath.setPoint( m_LinePath.count() - 1, pt );
02966 LinePath::Region r = ( region == South || region == North ) ?
02967 LinePath::TopBottom : LinePath::LeftRight;
02968 m_LinePath.setDockRegion( r );
02969 }
02970 }
02971
02972 void AssociationWidget::setSelected(bool _select ) {
02973 m_bSelected = _select;
02974 if( m_pName)
02975 m_pName-> setSelected( _select );
02976 if( m_role[A].m_pRole )
02977 m_role[A].m_pRole -> setSelected( _select );
02978 if( m_role[B].m_pRole )
02979 m_role[B].m_pRole -> setSelected( _select );
02980 if( m_role[A].m_pMulti )
02981 m_role[A].m_pMulti -> setSelected( _select );
02982 if( m_role[B].m_pMulti )
02983 m_role[B].m_pMulti -> setSelected( _select );
02984 if( m_role[A].m_pChangeWidget)
02985 m_role[A].m_pChangeWidget-> setSelected( _select );
02986 if( m_role[B].m_pChangeWidget)
02987 m_role[B].m_pChangeWidget-> setSelected( _select );
02988 kapp->processEvents();
02989
02990
02991
02992
02993 if( _select ) {
02994 if( m_pView -> getSelectCount() == 0 )
02995 m_pView -> showDocumentation( this, false );
02996 } else
02997 m_pView -> updateDocumentation( true );
02998 kapp->processEvents();
02999 m_LinePath.setSelected( _select );
03000 if (! _select) {
03001
03002
03003
03004
03005 selectAssocClassLine(false);
03006 }
03007 }
03008
03009 bool AssociationWidget::onAssocClassLine(const QPoint &point) {
03010 if (m_pAssocClassLine == NULL)
03011 return false;
03012 QCanvasItemList list = m_pView->canvas()->collisions(point);
03013 QCanvasItemList::iterator end(list.end());
03014 for (QCanvasItemList::iterator item_it(list.begin()); item_it != end; ++item_it) {
03015 if (*item_it == m_pAssocClassLine)
03016 return true;
03017 }
03018 return false;
03019 }
03020
03021 bool AssociationWidget::onAssociation(const QPoint & point) {
03022 if (m_LinePath.onLinePath(point) != -1)
03023 return true;
03024 return onAssocClassLine(point);
03025 }
03026
03027 void AssociationWidget::slotRemovePopupMenu()
03028 {
03029 if(m_pMenu) {
03030 disconnect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotMenuSelection(int)));
03031 delete m_pMenu;
03032 m_pMenu = 0;
03033 }
03034 }
03035
03036 void AssociationWidget::slotClearAllSelected() {
03037 setSelected( false );
03038 }
03039
03040 void AssociationWidget::moveMidPointsBy( int x, int y ) {
03041 int pos = m_LinePath.count() - 1;
03042 for( int i=1 ; i < (int)pos ; i++ ) {
03043 QPoint p = m_LinePath.getPoint( i );
03044 int newX = p.x() + x;
03045 int newY = p.y() + y;
03046 newX = m_pView -> snappedX( newX );
03047 newY = m_pView -> snappedY( newY );
03048 p.setX( newX );
03049 p.setY( newY );
03050 m_LinePath.setPoint( i, p );
03051 }
03052 }
03053
03054 void AssociationWidget::moveEntireAssoc( int x, int y ) {
03055
03056 moveMidPointsBy( x, y );
03057 calculateEndingPoints();
03058 calculateNameTextSegment();
03059 resetTextPositions();
03060 }
03061
03062 QRect AssociationWidget::getAssocLineRectangle()
03063 {
03064 QRect rectangle;
03065 QPoint p;
03066 uint pen_width;
03067
03068
03069 int pos = m_LinePath.count();
03070
03071
03072 for( int i=0 ; i < (int) pos; i++ )
03073 {
03074 p = m_LinePath.getPoint( i );
03075
03076
03077 if (i == 0) {
03078 rectangle.setRect(p.x(), p.y(), 0, 0);
03079 continue;
03080 }
03081
03082
03083 pen_width = m_LinePath.getPen().width();
03084 if (pen_width == 0)
03085 pen_width = 1;
03086
03087 if (p.x() < rectangle.x())
03088 rectangle.setX(p.x());
03089 if (p.y() < rectangle.y())
03090 rectangle.setY(p.y());
03091 if (p.x() > rectangle.x() + rectangle.width()) {
03092 int newX = p.x() - rectangle.x() + pen_width;
03093 rectangle.setWidth(abs(newX));
03094 }
03095 if (p.y() > rectangle.y() + rectangle.height()) {
03096 int newY = p.y() - rectangle.y() + pen_width;
03097 rectangle.setHeight(abs(newY));
03098 }
03099 }
03100 return rectangle;
03101 }
03102
03103 void AssociationWidget::setUMLObject(UMLObject *obj) {
03104 WidgetBase::setUMLObject(obj);
03105 if (obj == NULL)
03106 return;
03107 Uml::Object_Type ot = obj->getBaseType();
03108 if (ot == Uml::ot_Attribute) {
03109 UMLClassifier *klass = static_cast<UMLClassifier*>(obj->parent());
03110 connect(klass, SIGNAL(attributeRemoved(UMLClassifierListItem*)),
03111 this, SLOT(slotAttributeRemoved(UMLClassifierListItem*)));
03112 } else if (ot == Uml::ot_EntityAttribute) {
03113 UMLEntity *ent = static_cast<UMLEntity*>(obj->parent());
03114 connect(ent, SIGNAL(entityAttributeRemoved(UMLClassifierListItem*)),
03115 this, SLOT(slotAttributeRemoved(UMLClassifierListItem*)));
03116 }
03117 }
03118
03119 void AssociationWidget::slotAttributeRemoved(UMLClassifierListItem* obj) {
03120 if (obj != m_pObject)
03121 kDebug() << "AssociationWidget::slotAttributeRemoved:(obj=" << obj
03122 << "): m_pObject=" << m_pObject << endl;
03123 m_pObject = NULL;
03124 m_pView->removeAssoc(this);
03125 }
03126
03127 void AssociationWidget::init (UMLView *view)
03128 {
03129 WidgetBase::init(view, wt_Association);
03130
03131
03132 m_pName = 0;
03133 m_role[A].m_pChangeWidget = 0;
03134 m_role[B].m_pChangeWidget = 0;
03135 m_role[A].m_pMulti = 0;
03136 m_role[B].m_pMulti = 0;
03137 m_role[A].m_pRole = 0;
03138 m_role[B].m_pRole = 0;
03139 m_role[A].m_pWidget = 0;
03140 m_role[B].m_pWidget = 0;
03141
03142
03143 m_role[A].m_WidgetRegion = Error;
03144 m_role[B].m_WidgetRegion = Error;
03145 m_role[A].m_nIndex = 0;
03146 m_role[B].m_nIndex = 0;
03147 m_role[A].m_nTotalCount = 0;
03148 m_role[B].m_nTotalCount = 0;
03149 m_role[A].m_Visibility = Uml::Visibility::Public;
03150 m_role[B].m_Visibility = Uml::Visibility::Public;
03151 m_role[A].m_Changeability = Uml::chg_Changeable;
03152 m_role[B].m_Changeability = Uml::chg_Changeable;
03153 m_positions_len = 0;
03154 m_bActivated = false;
03155 m_unNameLineSegment = 0;
03156 m_pMenu = 0;
03157 m_bSelected = false;
03158 m_nMovingPoint = -1;
03159 m_nLinePathSegmentIndex = -1;
03160 m_pAssocClassWidget = NULL;
03161 m_pAssocClassLine = NULL;
03162 m_pAssocClassLineSel0 = m_pAssocClassLineSel1 = NULL;
03163
03164
03165
03166 m_AssocType = Uml::at_Association;
03167 m_umldoc = UMLApp::app()->getDocument();
03168 m_LinePath.setAssociation( this );
03169
03170 connect(m_pView, SIGNAL(sigRemovePopupMenu()), this, SLOT(slotRemovePopupMenu()));
03171 connect(m_pView, SIGNAL( sigClearAllSelected() ), this, SLOT( slotClearAllSelected() ) );
03172 }
03173
03174 void AssociationWidget::resetTextPositions() {
03175 if (m_role[A].m_pMulti) {
03176 setTextPosition( tr_MultiA );
03177 }
03178 if (m_role[B].m_pMulti) {
03179 setTextPosition( tr_MultiB );
03180 }
03181 if (m_role[A].m_pChangeWidget) {
03182 setTextPosition( tr_ChangeA );
03183 }
03184 if (m_role[B].m_pChangeWidget) {
03185 setTextPosition( tr_ChangeB );
03186 }
03187 if (m_pName) {
03188 setTextPosition( tr_Name );
03189 }
03190 if (m_role[A].m_pRole) {
03191 setTextPosition( tr_RoleAName );
03192 }
03193 if (m_role[B].m_pRole) {
03194 setTextPosition( tr_RoleBName );
03195 }
03196 }
03197
03198 void AssociationWidget::setIndex(int index, Role_Type role) {
03199 m_role[role].m_nIndex = index;
03200 }
03201
03202 int AssociationWidget::getIndex(Role_Type role) const {
03203 return m_role[role].m_nIndex;
03204 }
03205
03206 void AssociationWidget::setTotalCount(int count, Role_Type role) {
03207 m_role[role].m_nTotalCount = count;
03208 }
03209
03210 int AssociationWidget::getTotalCount(Role_Type role) const {
03211 return m_role[role].m_nTotalCount;
03212 }
03213
03214 UMLOperation *AssociationWidget::getOperation() {
03215 return dynamic_cast<UMLOperation*>(m_pObject);
03216 }
03217
03218 void AssociationWidget::setOperation(UMLOperation *op) {
03219 if (m_pObject)
03220 disconnect(m_pObject, SIGNAL(modified()), m_pName, SLOT(setMessageText()));
03221 m_pObject = op;
03222 if (m_pObject)
03223 connect(m_pObject, SIGNAL(modified()), m_pName, SLOT(setMessageText()));
03224 }
03225
03226 UMLClassifier *AssociationWidget::getOperationOwner() {
03227 Role_Type role = (isCollaboration() ? B : A);
03228 UMLObject *o = getWidget(role)->getUMLObject();
03229 if (o == NULL)
03230 return NULL;
03231 UMLClassifier *c = dynamic_cast<UMLClassifier*>(o);
03232 if (c == NULL)
03233 kError() << "AssociationWidget::getOperationOwner: "
03234 << "getWidget(" << role << ") is not a classifier"
03235 << endl;
03236 return c;
03237 }
03238
03239 void AssociationWidget::setSeqNumAndOp(const QString &seqNum, const QString &op) {
03240 if (! op.isEmpty())
03241 setName(op);
03242 setMulti(seqNum, A);
03243 }
03244
03245 UMLClassifier *AssociationWidget::getSeqNumAndOp(QString& seqNum, QString& op) {
03246 seqNum = getMulti(A);
03247 op = getName();
03248 UMLObject *o = getWidget(B)->getUMLObject();
03249 UMLClassifier *c = dynamic_cast<UMLClassifier*>(o);
03250 return c;
03251 }
03252
03253 void AssociationWidget::setCustomOpText(const QString &opText) {
03254 setName(opText);
03255 }
03256
03257 QString AssociationWidget::getCustomOpText() {
03258 return getName();
03259 }
03260
03261 void AssociationWidget::setWidget( UMLWidget* widget, Role_Type role) {
03262 m_role[role].m_pWidget = widget;
03263 if (widget) {
03264 m_role[role].m_pWidget->addAssoc(this);
03265 if (m_pObject && m_pObject->getBaseType() == ot_Association)
03266 getAssociation()->setObject(widget->getUMLObject(), role);
03267 }
03268 }
03269
03270 void AssociationWidget::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
03271 QDomElement assocElement = qDoc.createElement( "assocwidget" );
03272
03273 WidgetBase::saveToXMI(qDoc, assocElement);
03274 if (m_pObject) {
03275 assocElement.setAttribute( "xmi.id", ID2STR(m_pObject->getID()) );
03276 }
03277 assocElement.setAttribute( "type", m_AssocType );
03278 if (getAssociation() == NULL) {
03279 assocElement.setAttribute( "visibilityA", m_role[A].m_Visibility);
03280 assocElement.setAttribute( "visibilityB", m_role[B].m_Visibility);
03281 assocElement.setAttribute( "changeabilityA", m_role[A].m_Changeability);
03282 assocElement.setAttribute( "changeabilityB", m_role[B].m_Changeability);
03283 if (m_pObject == NULL) {
03284 assocElement.setAttribute( "roleAdoc", m_role[A].m_RoleDoc);
03285 assocElement.setAttribute( "roleBdoc", m_role[B].m_RoleDoc);
03286 assocElement.setAttribute( "documentation", m_Doc );
03287 }
03288 }
03289 assocElement.setAttribute( "widgetaid", ID2STR(getWidgetID(A)) );
03290 assocElement.setAttribute( "widgetbid", ID2STR(getWidgetID(B)) );
03291 assocElement.setAttribute( "indexa", m_role[A].m_nIndex );
03292 assocElement.setAttribute( "indexb", m_role[B].m_nIndex );
03293 assocElement.setAttribute( "totalcounta", m_role[A].m_nTotalCount );
03294 assocElement.setAttribute( "totalcountb", m_role[B].m_nTotalCount );
03295 m_LinePath.saveToXMI( qDoc, assocElement );
03296
03297 if( m_pName )
03298 m_pName -> saveToXMI( qDoc, assocElement );
03299
03300 if( m_role[A].m_pMulti )
03301 m_role[A].m_pMulti -> saveToXMI( qDoc, assocElement );
03302
03303 if( m_role[B].m_pMulti )
03304 m_role[B].m_pMulti -> saveToXMI( qDoc, assocElement );
03305
03306 if( m_role[A].m_pRole )
03307 m_role[A].m_pRole -> saveToXMI( qDoc, assocElement );
03308
03309 if( m_role[B].m_pRole )
03310 m_role[B].m_pRole -> saveToXMI( qDoc, assocElement );
03311
03312 if( m_role[A].m_pChangeWidget )
03313 m_role[A].m_pChangeWidget -> saveToXMI( qDoc, assocElement );
03314
03315 if( m_role[B].m_pChangeWidget )
03316 m_role[B].m_pChangeWidget -> saveToXMI( qDoc, assocElement );
03317
03318 if (m_pAssocClassWidget) {
03319 QString acid = ID2STR(m_pAssocClassWidget->getID());
03320 assocElement.setAttribute("assocclass", acid);
03321 assocElement.setAttribute("aclsegindex", m_nLinePathSegmentIndex);
03322 }
03323
03324 qElement.appendChild( assocElement );
03325 }
03326
03327 bool AssociationWidget::loadFromXMI( QDomElement & qElement,
03328 const UMLWidgetList& widgets,
03329 const MessageWidgetList* pMessages )
03330 {
03331 WidgetBase::loadFromXMI(qElement);
03332
03333
03334 QString widgetaid = qElement.attribute( "widgetaid", "-1" );
03335 QString widgetbid = qElement.attribute( "widgetbid", "-1" );
03336 Uml::IDType aId = STR2ID(widgetaid);
03337 Uml::IDType bId = STR2ID(widgetbid);
03338 UMLWidget *pWidgetA = Widget_Utils::findWidget( aId, widgets, pMessages );
03339 if (!pWidgetA) {
03340 kError() << "AssociationWidget::loadFromXMI(): "
03341 << "cannot find widget for roleA id " << ID2STR(aId) << endl;
03342 return false;
03343 }
03344 UMLWidget *pWidgetB = Widget_Utils::findWidget( bId, widgets, pMessages );
03345 if (!pWidgetB) {
03346 kError() << "AssociationWidget::loadFromXMI(): "
03347 << "cannot find widget for roleB id " << ID2STR(bId) << endl;
03348 return false;
03349 }
03350 setWidget(pWidgetA, A);
03351 setWidget(pWidgetB, B);
03352
03353 QString type = qElement.attribute( "type", "-1" );
03354 Uml::Association_Type aType = (Uml::Association_Type) type.toInt();
03355
03356 QString id = qElement.attribute( "xmi.id", "-1" );
03357 bool oldStyleLoad = false;
03358 if (id == "-1") {
03359
03360
03361
03362
03363
03364
03365
03366 if (UMLAssociation::assocTypeHasUMLRepresentation(aType)) {
03367
03368
03369
03370
03371
03372
03373 UMLObject* umlRoleA = pWidgetA->getUMLObject();
03374 UMLObject* umlRoleB = pWidgetB->getUMLObject();
03375 if (!m_pObject && umlRoleA && umlRoleB)
03376 {
03377 oldStyleLoad = true;
03378 if (aType == at_Aggregation || aType == at_Composition) {
03379 kWarning()<<" Old Style save file? swapping roles on association widget"<<this<<endl;
03380
03381
03382
03383
03384
03385
03386
03387
03388
03389
03390 UMLWidget *tmpWidget = pWidgetA;
03391 pWidgetA = pWidgetB;
03392 pWidgetB = tmpWidget;
03393 setWidget(pWidgetA, A);
03394 setWidget(pWidgetB, B);
03395 umlRoleA = pWidgetA->getUMLObject();
03396 umlRoleB = pWidgetB->getUMLObject();
03397 }
03398
03399 setUMLAssociation(m_umldoc->createUMLAssociation(umlRoleA, umlRoleB, aType));
03400 }
03401 }
03402
03403 setDoc( qElement.attribute("documentation", "") );
03404 setRoleDoc( qElement.attribute("roleAdoc", ""), A );
03405 setRoleDoc( qElement.attribute("roleBdoc", ""), B );
03406
03407
03408 QString visibilityA = qElement.attribute( "visibilityA", "0");
03409 if (visibilityA.toInt() > 0)
03410 setVisibility( (Uml::Visibility::Value)visibilityA.toInt(), A);
03411
03412 QString visibilityB = qElement.attribute( "visibilityB", "0");
03413 if (visibilityB.toInt() > 0)
03414 setVisibility( (Uml::Visibility::Value)visibilityB.toInt(), B);
03415
03416
03417 QString changeabilityA = qElement.attribute( "changeabilityA", "0");
03418 if (changeabilityA.toInt() > 0)
03419 setChangeability( (Changeability_Type)changeabilityA.toInt(), A);
03420
03421 QString changeabilityB = qElement.attribute( "changeabilityB", "0");
03422 if (changeabilityB.toInt() > 0)
03423 setChangeability( (Changeability_Type)changeabilityB.toInt(), B);
03424
03425 } else {
03426
03427
03428 if (m_pObject && m_pObject->getBaseType() == ot_Association)
03429 {
03430 UMLAssociation *umla = getAssociation();
03431 umla->disconnect(this);
03432 umla->nrof_parent_widgets--;
03433 }
03434
03435
03436
03437
03438 m_nId = STR2ID(id);
03439 UMLObject *myObj = m_umldoc->findObjectById(m_nId);
03440 if (myObj) {
03441 const Uml::Object_Type ot = myObj->getBaseType();
03442 if (ot != ot_Association) {
03443 setUMLObject(myObj);
03444 } else {
03445 UMLAssociation * myAssoc = static_cast<UMLAssociation*>(myObj);
03446 setUMLAssociation(myAssoc);
03447 if (type == "-1")
03448 aType = myAssoc->getAssocType();
03449 }
03450 }
03451 }
03452
03453 setAssocType(aType);
03454
03455 QString indexa = qElement.attribute( "indexa", "0" );
03456 QString indexb = qElement.attribute( "indexb", "0" );
03457 QString totalcounta = qElement.attribute( "totalcounta", "0" );
03458 QString totalcountb = qElement.attribute( "totalcountb", "0" );
03459 m_role[A].m_nIndex = indexa.toInt();
03460 m_role[B].m_nIndex = indexb.toInt();
03461 m_role[A].m_nTotalCount = totalcounta.toInt();
03462 m_role[B].m_nTotalCount = totalcountb.toInt();
03463
03464 QString assocclassid = qElement.attribute("assocclass", "");
03465 if (! assocclassid.isEmpty()) {
03466 Uml::IDType acid = STR2ID(assocclassid);
03467 UMLWidget *w = Widget_Utils::findWidget(acid, widgets);
03468 if (w) {
03469 m_pAssocClassWidget = static_cast<ClassifierWidget*>(w);
03470 m_pAssocClassWidget->setClassAssocWidget(this);
03471
03472 QString aclsegindex = qElement.attribute("aclsegindex", "0");
03473 m_nLinePathSegmentIndex = aclsegindex.toInt();
03474 } else {
03475 kError() << "AssociationWidget::loadFromXMI: "
03476 << "cannot find assocclass " << assocclassid
03477 << endl;
03478 }
03479 }
03480
03481
03482 QDomNode node = qElement.firstChild();
03483 QDomElement element = node.toElement();
03484 while( !element.isNull() ) {
03485 QString tag = element.tagName();
03486 if( tag == "linepath" ) {
03487 if( !m_LinePath.loadFromXMI( element ) )
03488 return false;
03489 else {
03490
03491
03492
03493
03494 QPoint p = m_LinePath.getPoint(0);
03495 m_role[A].m_OldCorner.setX(p.x());
03496 m_role[A].m_OldCorner.setY(p.y());
03497 }
03498 } else if (tag == "floatingtext" ||
03499 tag == "UML:FloatingTextWidget") {
03500 QString r = element.attribute( "role", "-1");
03501 if( r == "-1" )
03502 return false;
03503 Uml::Text_Role role = (Uml::Text_Role)r.toInt();
03504 FloatingTextWidget *ft = new FloatingTextWidget(m_pView, role, "", Uml::id_Reserved);
03505 if( ! ft->loadFromXMI(element) ) {
03506
03507 delete ft;
03508 node = element.nextSibling();
03509 element = node.toElement();
03510 continue;
03511 }
03512
03513 ft->setLink(this);
03514
03515 switch( role ) {
03516 case Uml::tr_MultiA:
03517 m_role[A].m_pMulti = ft;
03518 if(oldStyleLoad)
03519 setMulti(m_role[A].m_pMulti->getText(), A);
03520 break;
03521
03522 case Uml::tr_MultiB:
03523 m_role[B].m_pMulti = ft;
03524 if(oldStyleLoad)
03525 setMulti(m_role[B].m_pMulti->getText(), B);
03526 break;
03527
03528 case Uml::tr_ChangeA:
03529 m_role[A].m_pChangeWidget = ft;
03530 break;
03531
03532 case Uml::tr_ChangeB:
03533 m_role[B].m_pChangeWidget = ft;
03534 break;
03535
03536 case Uml::tr_Name:
03537 m_pName = ft;
03538 if(oldStyleLoad)
03539 setName(m_pName->getText());
03540 break;
03541
03542 case Uml::tr_Coll_Message:
03543 case Uml::tr_Coll_Message_Self:
03544 m_pName = ft;
03545 ft->setLink(this);
03546 ft->setActivated();
03547 if(FloatingTextWidget::isTextValid(ft->getText()))
03548 ft -> show();
03549 else
03550 ft -> hide();
03551 break;
03552
03553 case Uml::tr_RoleAName:
03554 m_role[A].m_pRole = ft;
03555 setRoleName( ft->getText(), A );
03556 break;
03557 case Uml::tr_RoleBName:
03558 m_role[B].m_pRole = ft;
03559 setRoleName( ft->getText(), B );
03560 break;
03561 default:
03562 kDebug() << "AssociationWidget::loadFromXMI(): "
03563 << "unexpected FloatingTextWidget (textrole "
03564 << role << ")" << endl;
03565 delete ft;
03566 break;
03567 }
03568 }
03569 node = element.nextSibling();
03570 element = node.toElement();
03571 }
03572
03573 return true;
03574 }
03575
03576 bool AssociationWidget::loadFromXMI( QDomElement & qElement ) {
03577 const MessageWidgetList& messages = m_pView->getMessageList();
03578 return loadFromXMI( qElement, m_pView->getWidgetList(), &messages );
03579 }
03580
03581 #include "associationwidget.moc"