/** * Moves the point or line if active. */ void AssociationLine::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { UMLScene* scene = m_associationWidget->umlScene(); QPointF oldPos = event->scenePos(); QPointF newPos( scene->snappedX(oldPos.x()), scene->snappedY(oldPos.y()) ); // Prevent the moving vertex from disappearing underneath a widget // (else there's no way to get it back.) UMLWidget *onW = scene->widgetAt(newPos); if (onW && onW->baseType() != WidgetBase::wt_Box) { // boxes are transparent const qreal pX = newPos.x(); const qreal pY = newPos.y(); const qreal wX = onW->x(); const qreal wY = onW->y(); const qreal wWidth = onW->width(); const qreal wHeight = onW->height(); if (pX > wX && pX < wX + wWidth) { const qreal midX = wX + wWidth / 2.0; if (pX <= midX) newPos.setX(wX); else newPos.setX(wX + wWidth); } if (pY > wY && pY < wY + wHeight) { const qreal midY = wY + wHeight / 2.0; if (pY <= midY) newPos.setY(wY); else newPos.setY(wY + wHeight); } } if (m_activePointIndex != -1) { // Move a single point (snap behaviour) setPoint(m_activePointIndex, newPos); } else if (m_activeSegmentIndex != -1 && !isEndSegmentIndex(m_activeSegmentIndex)) { // Move a segment (between two points, snap behaviour not implemented) QPointF delta = event->scenePos() - event->lastScenePos(); setPoint(m_activeSegmentIndex, m_points[m_activeSegmentIndex] + delta); setPoint(m_activeSegmentIndex + 1, m_points[m_activeSegmentIndex + 1] + delta); } }
/** * Sets the second widget in the association using the current widget and * creates the association. * If the association between the two widgets using the current type of * association is illegitimate, an error is shown and the association cancelled. * Otherwise, the association is created and added to the scene, and the tool * is changed to the default tool. * * @todo Why change to the default tool? Shouldn't it better to stay on * association and let the user change with a right click? The tool to * create widgets doesn't change to default after creating a widget */ void ToolBarStateAssociation::setSecondWidget() { Uml::AssociationType::Enum type = getAssociationType(); UMLWidget* widgetA = m_firstWidget; UMLWidget* widgetB = currentWidget(); WidgetBase::WidgetType at = widgetA->baseType(); bool valid = true; if (type == Uml::AssociationType::Generalization) { type = AssocRules::isGeneralisationOrRealisation(widgetA, widgetB); } if (widgetA == widgetB) { valid = AssocRules::allowSelf(type, at); if (valid && type == Uml::AssociationType::Association) { type = Uml::AssociationType::Association_Self; } } else { valid = AssocRules::allowAssociation(type, widgetA, widgetB); } if (valid) { AssociationWidget *temp = AssociationWidget::create(m_pUMLScene, widgetA, type, widgetB); FloatingTextWidget *wt = temp->textWidgetByRole(Uml::TextRole::Coll_Message); if (wt) wt->showOperationDialog(); if (addAssociationInViewAndDoc(temp)) { if (type == Uml::AssociationType::Containment) { UMLObject *newContainer = widgetA->umlObject(); UMLObject *objToBeMoved = widgetB->umlObject(); if (newContainer && objToBeMoved) { Model_Utils::treeViewMoveObjectTo(newContainer, objToBeMoved); } } UMLApp::app()->document()->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(); }