You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdesdk/umbrello/umbrello/toolbarstateassociation.cpp

233 lines
8.2 KiB

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* copyright (C) 2004-2006 *
* Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
***************************************************************************/
// own header
#include "toolbarstateassociation.h"
// kde includes
#include <kdebug.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
// app includes
#include "assocrules.h"
#include "association.h"
#include "associationwidget.h"
#include "classifierwidget.h"
#include "folder.h"
#include "model_utils.h"
#include "uml.h"
#include "umlobject.h"
#include "umlview.h"
#include "umllistview.h"
#include "umldoc.h"
#include "umlwidget.h"
using namespace Uml;
ToolBarStateAssociation::ToolBarStateAssociation(UMLView *umlView) : ToolBarStatePool(umlView) {
m_firstWidget = 0;
m_associationLine = 0;
}
ToolBarStateAssociation::~ToolBarStateAssociation() {
delete m_associationLine;
}
void ToolBarStateAssociation::init() {
ToolBarStatePool::init();
cleanAssociation();
}
void ToolBarStateAssociation::cleanBeforeChange() {
ToolBarStatePool::cleanBeforeChange();
cleanAssociation();
}
void ToolBarStateAssociation::mouseMove(TQMouseEvent* ome) {
ToolBarStatePool::mouseMove(ome);
if (m_associationLine) {
TQPoint sp = m_associationLine->startPoint();
m_associationLine->setPoints(sp.x(), sp.y(), m_pMouseEvent->x(), m_pMouseEvent->y());
}
}
void ToolBarStateAssociation::slotWidgetRemoved(UMLWidget* widget) {
ToolBarState::slotWidgetRemoved(widget);
if (widget == m_firstWidget) {
cleanAssociation();
}
}
void ToolBarStateAssociation::mouseReleaseAssociation() {
if (m_pMouseEvent->button() != TQt::LeftButton ||
!m_firstWidget || m_firstWidget->getBaseType() != Uml::wt_Class) {
cleanAssociation();
return;
}
getCurrentAssociation()->createAssocClassLine(
static_cast<ClassifierWidget*>(m_firstWidget),
getCurrentAssociation()->getLinePath()->onLinePath(m_pMouseEvent->pos()));
cleanAssociation();
}
void ToolBarStateAssociation::mouseReleaseWidget() {
if (m_pMouseEvent->button() != TQt::LeftButton) {
cleanAssociation();
return;
}
// TODO In old code in ToolBarState there was a TODO that said: Should not
//be called by a Sequence message Association. Here's the check for that,
//although I don't know why it is needed, but it seems that it's not needed,
//as the old code worked fine without it...
if (getAssociationType() == at_Seq_Message) {
return;
}
if (!m_firstWidget) {
setFirstWidget();
} else {
setSecondWidget();
}
}
void ToolBarStateAssociation::mouseReleaseEmpty() {
cleanAssociation();
}
void ToolBarStateAssociation::setFirstWidget() {
UMLWidget* widget = getCurrentWidget();
Association_Type type = getAssociationType();
if (!AssocRules::allowAssociation(type, widget)) {
//TODO improve error feedback: tell the user what are the valid type of associations for
//that widget
KMessageBox::error(0, i18n("Incorrect use of associations."), i18n("Association Error"));
return;
}
//set up position
TQPoint pos;
pos.setX(widget->getX() + (widget->getWidth() / 2));
pos.setY(widget->getY() + (widget->getHeight() / 2));
//TODO why is this needed?
m_pUMLView->setPos(pos);
m_firstWidget = widget;
m_associationLine = new TQCanvasLine(m_pUMLView->canvas());
m_associationLine->setPoints(pos.x(), pos.y(), pos.x(), pos.y());
m_associationLine->setPen(TQPen(m_pUMLView->getLineColor(), m_pUMLView->getLineWidth(), TQt::DashLine));
m_associationLine->setVisible(true);
m_pUMLView->viewport()->setMouseTracking(true);
}
void ToolBarStateAssociation::setSecondWidget() {
Association_Type type = getAssociationType();
UMLWidget* widgetA = m_firstWidget;
UMLWidget* widgetB = getCurrentWidget();
Widget_Type at = widgetA->getBaseType();
bool valid = true;
if (type == at_Generalization) {
type = AssocRules::isGeneralisationOrRealisation(widgetA, widgetB);
}
if (widgetA == widgetB) {
valid = AssocRules::allowSelf(type, at);
if (valid && type == at_Association) {
type = at_Association_Self;
}
} else {
valid = AssocRules::allowAssociation(type, widgetA, widgetB);
}
if (valid) {
AssociationWidget *temp = new AssociationWidget(m_pUMLView, widgetA, type, widgetB);
addAssociationInViewAndDoc(temp);
if (type == at_Containment) {
UMLListView *lv = UMLApp::app()->getListView();
UMLObject *newContainer = widgetA->getUMLObject();
UMLObject *objToBeMoved = widgetB->getUMLObject();
if (newContainer && objToBeMoved) {
UMLListViewItem *newLVParent = lv->findUMLObject(newContainer);
lv->moveObject(objToBeMoved->getID(),
Model_Utils::convert_OT_LVT(objToBeMoved),
newLVParent);
}
}
UMLApp::app()->getDocument()->setModified();
} else {
//TODO improve error feedback: tell the user what are the valid type of associations for
//the second widget using the first widget
KMessageBox::error(0, i18n("Incorrect use of associations."), i18n("Association Error"));
}
cleanAssociation();
}
Association_Type ToolBarStateAssociation::getAssociationType() {
Association_Type at;
switch(getButton()) {
case WorkToolBar::tbb_Anchor: at = at_Anchor; break;
case WorkToolBar::tbb_Association: at = at_Association; break;
case WorkToolBar::tbb_UniAssociation: at = at_UniAssociation; break;
case WorkToolBar::tbb_Generalization: at = at_Generalization; break;
case WorkToolBar::tbb_Composition: at = at_Composition; break;
case WorkToolBar::tbb_Aggregation: at = at_Aggregation; break;
case WorkToolBar::tbb_Relationship: at = at_Relationship; break;
case WorkToolBar::tbb_Dependency: at = at_Dependency; break;
case WorkToolBar::tbb_Containment: at = at_Containment; break;
case WorkToolBar::tbb_Seq_Message_Synchronous:
case WorkToolBar::tbb_Seq_Message_Asynchronous: at = at_Seq_Message; break;
case WorkToolBar::tbb_Coll_Message: at = at_Coll_Message; break;
case WorkToolBar::tbb_State_Transition: at = at_State; break;
case WorkToolBar::tbb_Activity_Transition: at = at_Activity; break;
default: at = at_Unknown; break;
}
return at;
}
void ToolBarStateAssociation::addAssociationInViewAndDoc(AssociationWidget* a) {
// append in view
if (m_pUMLView->addAssociation(a, false)) {
// if view went ok, then append in document
UMLAssociation *umla = a->getAssociation();
if (umla == NULL) {
// association without model representation in UMLDoc
return;
}
Uml::Model_Type m = Model_Utils::convert_DT_MT(m_pUMLView->getType());
UMLDoc *umldoc = UMLApp::app()->getDocument();
umla->setUMLPackage(umldoc->getRootFolder(m));
UMLApp::app()->getDocument()->addAssociation(umla);
} else {
kError() << "cannot addAssocInViewAndDoc(), deleting" << endl;
delete a;
}
}
void ToolBarStateAssociation::cleanAssociation() {
m_firstWidget = 0;
delete m_associationLine;
m_associationLine = 0;
}
#include "toolbarstateassociation.moc"