From 82cb2b248e35f5dbf1a27beb9295c56c4cad4478 Mon Sep 17 00:00:00 2001 From: Jochen Becher Date: Sat, 20 Aug 2016 21:46:55 +0200 Subject: [PATCH] ModelEditor: Show relation templates in object toolbars Change-Id: I06de22538e500c133693ff0c791ac8a2d3be3402 Reviewed-by: Tobias Hunger --- .../qmt/diagram_scene/diagramscenemodel.cpp | 17 +- .../qmt/diagram_scene/diagramscenemodel.h | 2 + .../qmt/diagram_scene/items/classitem.cpp | 160 +++++++++++++++--- .../qmt/diagram_scene/items/classitem.h | 6 +- .../qmt/diagram_scene/items/componentitem.cpp | 25 +-- .../qmt/diagram_scene/items/componentitem.h | 1 - .../qmt/diagram_scene/items/diagramitem.cpp | 2 +- .../qmt/diagram_scene/items/itemitem.cpp | 25 +-- .../qmt/diagram_scene/items/itemitem.h | 1 - .../qmt/diagram_scene/items/objectitem.cpp | 156 +++++++++++++++-- .../qmt/diagram_scene/items/objectitem.h | 13 +- .../qmt/diagram_scene/items/packageitem.cpp | 24 +-- .../qmt/diagram_scene/items/packageitem.h | 1 - .../qmt/diagram_scene/parts/arrowitem.cpp | 141 +++++++++++---- .../qmt/diagram_scene/parts/arrowitem.h | 18 +- .../diagram_scene/parts/relationstarter.cpp | 10 +- .../qmt/diagram_scene/parts/relationstarter.h | 5 +- .../qmt/tasks/diagramscenecontroller.cpp | 9 +- .../qmt/tasks/diagramscenecontroller.h | 7 +- 19 files changed, 464 insertions(+), 159 deletions(-) diff --git a/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.cpp b/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.cpp index 673387fb6d1..f26c31cc6b1 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.cpp +++ b/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.cpp @@ -38,6 +38,7 @@ #include "qmt/diagram/drelation.h" #include "qmt/diagram_controller/diagramcontroller.h" #include "qmt/diagram_controller/dselection.h" +#include "qmt/diagram_scene/items/objectitem.h" #include "qmt/model/mdiagram.h" #include "qmt/model/mobject.h" #include "qmt/model/mpackage.h" @@ -229,17 +230,25 @@ DElement *DiagramSceneModel::findTopmostElement(const QPointF &scenePos) const } DObject *DiagramSceneModel::findTopmostObject(const QPointF &scenePos) const +{ + ObjectItem *item = findTopmostObjectItem(scenePos); + if (!item) + return nullptr; + return item->object(); +} + +ObjectItem *DiagramSceneModel::findTopmostObjectItem(const QPointF &scenePos) const { // fetch affected items from scene in correct drawing order to find topmost element - QList items = m_graphicsScene->items(scenePos); - foreach (QGraphicsItem *item, items) { + const QList items = m_graphicsScene->items(scenePos); + for (QGraphicsItem *item : items) { if (m_graphicsItems.contains(item)) { DObject *object = dynamic_cast(m_itemToElementMap.value(item)); if (object) - return object; + return dynamic_cast(item); } } - return 0; + return nullptr; } QGraphicsItem *DiagramSceneModel::graphicsItem(DElement *element) const diff --git a/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.h b/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.h index 1b616710cfa..1a5b0c64ea0 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.h +++ b/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodel.h @@ -54,6 +54,7 @@ class DSelection; class MDiagram; class DElement; class DObject; +class ObjectItem; class QMT_EXPORT DiagramSceneModel : public QObject { @@ -98,6 +99,7 @@ public: DSelection selectedElements() const; DElement *findTopmostElement(const QPointF &scenePos) const; DObject *findTopmostObject(const QPointF &scenePos) const; + ObjectItem *findTopmostObjectItem(const QPointF &scenePos) const; QList graphicsItems() const { return m_graphicsItems; } QGraphicsItem *graphicsItem(DElement *element) const; diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp index b1f3c5fb6b4..ca37e4ea6a1 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp +++ b/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp @@ -40,6 +40,7 @@ #include "qmt/infrastructure/qmtassert.h" #include "qmt/model/mclass.h" #include "qmt/model/mclassmember.h" +#include "qmt/model/massociation.h" #include "qmt/model_controller/modelcontroller.h" #include "qmt/stereotype/stereotypecontroller.h" #include "qmt/stereotype/stereotypeicon.h" @@ -59,15 +60,20 @@ #include +#include + namespace qmt { +static const char ASSOCIATION[] = "association"; +static const char INHERITANCE[] = "inheritance"; + static const qreal MINIMUM_AUTO_WIDTH = 80.0; static const qreal MINIMUM_AUTO_HEIGHT = 60.0; static const qreal BODY_VERT_BORDER = 4.0; static const qreal BODY_HORIZ_BORDER = 4.0; ClassItem::ClassItem(DClass *klass, DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent) - : ObjectItem(klass, diagramSceneModel, parent) + : ObjectItem(QStringLiteral("class"), klass, diagramSceneModel, parent) { } @@ -247,30 +253,83 @@ QSizeF ClassItem::minimumSize() const return calcMinimumGeometry(); } -void ClassItem::relationDrawn(const QString &id, const QPointF &toScenePos, const QList &intermediatePoints) +void ClassItem::relationDrawn(const QString &id, ObjectItem *targetItem, const QList &intermediatePoints) { - DElement *targetElement = diagramSceneModel()->findTopmostElement(toScenePos); - if (targetElement) { - if (id == QLatin1String("inheritance")) { - auto baseClass = dynamic_cast(targetElement); - if (baseClass) { - auto derivedClass = dynamic_cast(object()); - QMT_ASSERT(derivedClass, return); - diagramSceneModel()->diagramSceneController()->createInheritance(derivedClass, baseClass, intermediatePoints, diagramSceneModel()->diagram()); + DiagramSceneController *diagramSceneController = diagramSceneModel()->diagramSceneController(); + if (id == INHERITANCE) { + auto baseClass = dynamic_cast(targetItem->object()); + if (baseClass) { + auto derivedClass = dynamic_cast(object()); + QMT_ASSERT(derivedClass, return); + diagramSceneController->createInheritance(derivedClass, baseClass, intermediatePoints, diagramSceneModel()->diagram()); + } + return; + } else if (id == ASSOCIATION) { + auto associatedClass = dynamic_cast(targetItem->object()); + if (associatedClass) { + auto derivedClass = dynamic_cast(object()); + QMT_ASSERT(derivedClass, return); + diagramSceneController->createAssociation(derivedClass, associatedClass, intermediatePoints, diagramSceneModel()->diagram()); + } + return; + } else { + StereotypeController *stereotypeController = diagramSceneModel()->stereotypeController(); + CustomRelation customRelation = stereotypeController->findCustomRelation(id); + if (!customRelation.isNull()) { + switch (customRelation.element()) { + case CustomRelation::Element::Inheritance: + { + auto baseClass = dynamic_cast(targetItem->object()); + if (baseClass) { + auto derivedClass = dynamic_cast(object()); + QMT_ASSERT(derivedClass, return); + diagramSceneController->createInheritance(derivedClass, baseClass, intermediatePoints, diagramSceneModel()->diagram()); + } + return; } - } else if (id == QLatin1String("dependency")) { - auto dependantObject = dynamic_cast(targetElement); - if (dependantObject) - diagramSceneModel()->diagramSceneController()->createDependency(object(), dependantObject, intermediatePoints, diagramSceneModel()->diagram()); - } else if (id == QLatin1String("association")) { - auto assoziatedClass = dynamic_cast(targetElement); - if (assoziatedClass) { - auto derivedClass = dynamic_cast(object()); - QMT_ASSERT(derivedClass, return); - diagramSceneModel()->diagramSceneController()->createAssociation(derivedClass, assoziatedClass, intermediatePoints, diagramSceneModel()->diagram()); + case CustomRelation::Element::Association: + { + auto assoziatedClass = dynamic_cast(targetItem->object()); + if (assoziatedClass) { + auto derivedClass = dynamic_cast(object()); + QMT_ASSERT(derivedClass, return); + diagramSceneController->createAssociation( + derivedClass, assoziatedClass, intermediatePoints, diagramSceneModel()->diagram(), + [=] (MAssociation *mAssociation, DAssociation *dAssociation) { + if (mAssociation && dAssociation) { + static const QHash relationship2KindMap = { + { CustomRelation::Relationship::Association, MAssociationEnd::Association }, + { CustomRelation::Relationship::Aggregation, MAssociationEnd::Aggregation }, + { CustomRelation::Relationship::Composition, MAssociationEnd::Composition } }; + diagramSceneController->modelController()->startUpdateRelation(mAssociation); + mAssociation->setStereotypes(customRelation.stereotypes().toList()); + mAssociation->setName(customRelation.name()); + MAssociationEnd endA; + endA.setCardinality(customRelation.endA().cardinality()); + endA.setKind(relationship2KindMap.value(customRelation.endA().relationship())); + endA.setName(customRelation.endA().role()); + endA.setNavigable(customRelation.endA().navigable()); + mAssociation->setEndA(endA); + MAssociationEnd endB; + endB.setCardinality(customRelation.endB().cardinality()); + endB.setKind(relationship2KindMap.value(customRelation.endB().relationship())); + endB.setName(customRelation.endB().role()); + endB.setNavigable(customRelation.endB().navigable()); + mAssociation->setEndB(endB); + diagramSceneController->modelController()->finishUpdateRelation(mAssociation, false); + } + }); + } + return; + } + case CustomRelation::Element::Dependency: + case CustomRelation::Element::Relation: + // fall thru + break; } } } + ObjectItem::relationDrawn(id, targetItem, intermediatePoints); } bool ClassItem::extendContextMenu(QMenu *menu) @@ -338,11 +397,64 @@ void ClassItem::setFromDisplayName(const QString &displayName) } } -void ClassItem::updateRelationStarterTools(RelationStarter *relationStarter) +void ClassItem::addRelationStarterTool(const QString &id) { - relationStarter->addArrow("dependency", ArrowItem::ShaftDashed, ArrowItem::HeadOpen); - relationStarter->addArrow("inheritance", ArrowItem::ShaftSolid, ArrowItem::HeadTriangle); - relationStarter->addArrow("association", ArrowItem::ShaftSolid, ArrowItem::HeadFilledTriangle); + if (id == INHERITANCE) + relationStarter()->addArrow(INHERITANCE, ArrowItem::ShaftSolid, + ArrowItem::HeadNone, ArrowItem::HeadTriangle, + tr("Inheritance")); + else if (id == ASSOCIATION) + relationStarter()->addArrow(ASSOCIATION, ArrowItem::ShaftSolid, + ArrowItem::HeadNone, ArrowItem::HeadFilledTriangle, + tr("Association")); + else + ObjectItem::addRelationStarterTool(id); +} + +void ClassItem::addRelationStarterTool(const CustomRelation &customRelation) +{ + ArrowItem::Shaft shaft = ArrowItem::ShaftSolid; + ArrowItem::Head headStart = ArrowItem::HeadNone; + ArrowItem::Head headEnd = ArrowItem::HeadNone; + switch (customRelation.element()) { + case CustomRelation::Element::Inheritance: + shaft = ArrowItem::ShaftSolid; + headEnd = ArrowItem::HeadTriangle; + break; + case CustomRelation::Element::Association: + switch (customRelation.endA().relationship()) { + case CustomRelation::Relationship::Association: + if (customRelation.endA().navigable() && customRelation.endB().navigable()) { + headStart = ArrowItem::HeadNone; + headEnd = ArrowItem::HeadNone; + } else if (customRelation.endA().navigable()) { + headStart = ArrowItem::HeadFilledTriangle; + } else { + headEnd = ArrowItem::HeadFilledTriangle; + } + break; + case CustomRelation::Relationship::Aggregation: + headStart = ArrowItem::HeadDiamond; + break; + case CustomRelation::Relationship::Composition: + headStart = ArrowItem::HeadFilledDiamond; + break; + } + break; + case CustomRelation::Element::Dependency: + case CustomRelation::Element::Relation: + ObjectItem::addRelationStarterTool(customRelation); + return; + } + relationStarter()->addArrow(customRelation.id(), shaft, headStart, headEnd, + customRelation.title()); +} + +void ClassItem::addStandardRelationStarterTools() +{ + ObjectItem::addStandardRelationStarterTools(); + addRelationStarterTool(INHERITANCE); + addRelationStarterTool(ASSOCIATION); } DClass::TemplateDisplay ClassItem::templateDisplay() const diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/classitem.h b/src/libs/modelinglib/qmt/diagram_scene/items/classitem.h index fb54cceedbd..bb073cf6bda 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/items/classitem.h +++ b/src/libs/modelinglib/qmt/diagram_scene/items/classitem.h @@ -59,7 +59,7 @@ public: QSizeF minimumSize() const override; - void relationDrawn(const QString &id, const QPointF &toScenePos, + void relationDrawn(const QString &id, ObjectItem *targetElement, const QList &intermediatePoints) override; protected: @@ -67,7 +67,9 @@ protected: bool handleSelectedContextMenuAction(const QString &id) override; QString buildDisplayName() const override; void setFromDisplayName(const QString &displayName) override; - void updateRelationStarterTools(RelationStarter *relationStarter) override; + void addRelationStarterTool(const QString &id) override; + void addRelationStarterTool(const CustomRelation &customRelation) override; + void addStandardRelationStarterTools() override; private: DClass::TemplateDisplay templateDisplay() const; diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp index 0b6dcb5037a..2f357191ed7 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp +++ b/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.cpp @@ -32,7 +32,6 @@ #include "qmt/diagram_scene/parts/contextlabelitem.h" #include "qmt/diagram_scene/parts/customiconitem.h" #include "qmt/diagram_scene/parts/editabletextitem.h" -#include "qmt/diagram_scene/parts/relationstarter.h" #include "qmt/diagram_scene/parts/stereotypesitem.h" #include "qmt/infrastructure/geometryutilities.h" #include "qmt/infrastructure/qmtassert.h" @@ -61,7 +60,7 @@ static const qreal BODY_VERT_BORDER = 4.0; static const qreal BODY_HORIZ_BORDER = 4.0; ComponentItem::ComponentItem(DComponent *component, DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent) - : ObjectItem(component, diagramSceneModel, parent) + : ObjectItem(QStringLiteral("component"), component, diagramSceneModel, parent) { } @@ -154,22 +153,7 @@ void ComponentItem::update() } updateSelectionMarker(m_customIcon); - - // relation starters - if (isFocusSelected()) { - if (!m_relationStarter && scene()) { - m_relationStarter = new RelationStarter(this, diagramSceneModel(), 0); - scene()->addItem(m_relationStarter); - m_relationStarter->setZValue(RELATION_STARTER_ZVALUE); - m_relationStarter->addArrow(QStringLiteral("dependency"), ArrowItem::ShaftDashed, ArrowItem::HeadOpen); - } - } else if (m_relationStarter) { - if (m_relationStarter->scene()) - m_relationStarter->scene()->removeItem(m_relationStarter); - delete m_relationStarter; - m_relationStarter = 0; - } - + updateRelationStarter(); updateAlignmentButtons(); updateGeometry(); } @@ -344,10 +328,7 @@ void ComponentItem::updateGeometry() } updateSelectionMarkerGeometry(rect); - - if (m_relationStarter) - m_relationStarter->setPos(mapToScene(QPointF(right + 8.0, top))); - + updateRelationStarterGeometry(rect); updateAlignmentButtonsGeometry(rect); updateDepth(); } diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.h b/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.h index bbf749e785b..2c95f3e7a12 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.h +++ b/src/libs/modelinglib/qmt/diagram_scene/items/componentitem.h @@ -68,7 +68,6 @@ private: QGraphicsRectItem *m_upperRect = 0; QGraphicsRectItem *m_lowerRect = 0; ContextLabelItem *m_contextLabel = 0; - RelationStarter *m_relationStarter = 0; }; } // namespace qmt diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp index 01feb195a1e..3cc710ff8b8 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp +++ b/src/libs/modelinglib/qmt/diagram_scene/items/diagramitem.cpp @@ -54,7 +54,7 @@ static const qreal BODY_HORIZ_BORDER = 4.0; static const qreal BODY_VERT_BORDER = 4.0; DiagramItem::DiagramItem(DDiagram *diagram, DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent) - : ObjectItem(diagram, diagramSceneModel, parent) + : ObjectItem(QStringLiteral("diagram"), diagram, diagramSceneModel, parent) { } diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp index db3709cd466..e919c486a44 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp +++ b/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.cpp @@ -32,7 +32,6 @@ #include "qmt/diagram_scene/parts/contextlabelitem.h" #include "qmt/diagram_scene/parts/customiconitem.h" #include "qmt/diagram_scene/parts/editabletextitem.h" -#include "qmt/diagram_scene/parts/relationstarter.h" #include "qmt/diagram_scene/parts/stereotypesitem.h" #include "qmt/infrastructure/geometryutilities.h" #include "qmt/infrastructure/qmtassert.h" @@ -56,7 +55,7 @@ static const qreal BODY_VERT_BORDER = 4.0; static const qreal BODY_HORIZ_BORDER = 4.0; ItemItem::ItemItem(DItem *item, DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent) - : ObjectItem(item, diagramSceneModel, parent) + : ObjectItem(QStringLiteral("item"), item, diagramSceneModel, parent) { } @@ -124,22 +123,7 @@ void ItemItem::update() } updateSelectionMarker(m_customIcon); - - // relation starters - if (isFocusSelected()) { - if (!m_relationStarter && scene()) { - m_relationStarter = new RelationStarter(this, diagramSceneModel(), 0); - scene()->addItem(m_relationStarter); - m_relationStarter->setZValue(RELATION_STARTER_ZVALUE); - m_relationStarter->addArrow(QStringLiteral("dependency"), ArrowItem::ShaftDashed, ArrowItem::HeadOpen); - } - } else if (m_relationStarter) { - if (m_relationStarter->scene()) - m_relationStarter->scene()->removeItem(m_relationStarter); - delete m_relationStarter; - m_relationStarter = 0; - } - + updateRelationStarter(); updateAlignmentButtons(); updateGeometry(); } @@ -277,10 +261,7 @@ void ItemItem::updateGeometry() } updateSelectionMarkerGeometry(rect); - - if (m_relationStarter) - m_relationStarter->setPos(mapToScene(QPointF(right + 8.0, top))); - + updateRelationStarterGeometry(rect); updateAlignmentButtonsGeometry(rect); updateDepth(); } diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.h b/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.h index fbf9abd2ed1..9d3e2338a5c 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.h +++ b/src/libs/modelinglib/qmt/diagram_scene/items/itemitem.h @@ -64,7 +64,6 @@ private: CustomIconItem *m_customIcon = 0; QGraphicsRectItem *m_shape = 0; ContextLabelItem *m_contextLabel = 0; - RelationStarter *m_relationStarter = 0; }; } // namespace qmt diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp index 22b3f627699..d244f5366d8 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp +++ b/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp @@ -42,7 +42,9 @@ #include "qmt/model/mdiagram.h" #include "qmt/model/mobject.h" #include "qmt/model_controller/modelcontroller.h" +#include "qmt/stereotype/customrelation.h" #include "qmt/stereotype/stereotypecontroller.h" +#include "qmt/stereotype/toolbar.h" #include "qmt/style/style.h" #include "qmt/style/stylecontroller.h" #include "qmt/style/styledobject.h" @@ -58,8 +60,12 @@ namespace qmt { -ObjectItem::ObjectItem(DObject *object, DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent) +static const char DEPENDENCY[] = "dependency"; + + +ObjectItem::ObjectItem(const QString &elementType, DObject *object, DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent) : QGraphicsItem(parent), + m_elementType(elementType), m_object(object), m_diagramSceneModel(diagramSceneModel) { @@ -309,12 +315,58 @@ QPointF ObjectItem::relationStartPos() const void ObjectItem::relationDrawn(const QString &id, const QPointF &toScenePos, const QList &intermediatePoints) { - DElement *targetElement = diagramSceneModel()->findTopmostElement(toScenePos); - if (targetElement) { - if (id == QLatin1String("dependency")) { - auto dependantObject = dynamic_cast(targetElement); - if (dependantObject) - diagramSceneModel()->diagramSceneController()->createDependency(object(), dependantObject, intermediatePoints, diagramSceneModel()->diagram()); + ObjectItem *targetItem = diagramSceneModel()->findTopmostObjectItem(toScenePos); + if (targetItem) + relationDrawn(id, targetItem, intermediatePoints); +} + +void ObjectItem::relationDrawn(const QString &id, ObjectItem *targetItem, const QList &intermediatePoints) +{ + DiagramSceneController *diagramSceneController = diagramSceneModel()->diagramSceneController(); + if (id == DEPENDENCY) { + DObject *dependantObject = targetItem->object(); + if (dependantObject) + diagramSceneController->createDependency(object(), dependantObject, intermediatePoints, + diagramSceneModel()->diagram()); + } else { + StereotypeController *stereotypeController = diagramSceneModel()->stereotypeController(); + CustomRelation customRelation = stereotypeController->findCustomRelation(id); + if (!customRelation.isNull()) { + switch (customRelation.element()) { + case CustomRelation::Element::Dependency: + { + DObject *dependantObject = targetItem->object(); + if (dependantObject) + diagramSceneController->createDependency(object(), dependantObject, intermediatePoints, + diagramSceneModel()->diagram()); + break; + } + case CustomRelation::Element::Relation: + { + DObject *relatedObject = targetItem->object(); + if (relatedObject) { + // check if element is allowed as target + QList endItems = customRelation.endB().endItems(); + if (endItems.isEmpty()) + endItems = customRelation.endItems(); + QString elementType; + if (!targetItem->stereotypeIconId().isEmpty()) + elementType = targetItem->stereotypeIconId(); + else if (!targetItem->shapeIconId().isEmpty()) + elementType = targetItem->shapeIconId(); + else + elementType = targetItem->elementType(); + if (!endItems.contains(elementType)) { + return; + } + // create relation + } + break; + } + default: + // ignore other elements + break; + } } } } @@ -594,7 +646,29 @@ void ObjectItem::updateRelationStarter() m_relationStarter = new RelationStarter(this, diagramSceneModel(), 0); scene()->addItem(m_relationStarter); m_relationStarter->setZValue(RELATION_STARTER_ZVALUE); - updateRelationStarterTools(m_relationStarter); + QString elementType; + if (!m_stereotypeIconId.isEmpty()) + elementType = m_stereotypeIconId; + else if (!m_shapeIconId.isEmpty()) + elementType = m_shapeIconId; + else + elementType = m_elementType; + StereotypeController *stereotypeController = diagramSceneModel()->stereotypeController(); + QList toolbars = stereotypeController->findToolbars(elementType); + if (!toolbars.isEmpty()) { + foreach (const Toolbar &toolbar, toolbars) { + foreach (const Toolbar::Tool &tool, toolbar.tools()) { + CustomRelation customRelation = + stereotypeController->findCustomRelation(tool.m_elementType); + if (!customRelation.isNull()) + addRelationStarterTool(customRelation); + else + addRelationStarterTool(tool.m_elementType); + } + } + } else { + addStandardRelationStarterTools(); + } } } else if (m_relationStarter) { scene()->removeItem(m_relationStarter); @@ -604,9 +678,71 @@ void ObjectItem::updateRelationStarter() } -void ObjectItem::updateRelationStarterTools(RelationStarter *relationStarter) +void ObjectItem::addRelationStarterTool(const QString &id) { - relationStarter->addArrow(QLatin1String("dependency"), ArrowItem::ShaftDashed, ArrowItem::HeadOpen); + if (id == DEPENDENCY) + m_relationStarter->addArrow(DEPENDENCY, ArrowItem::ShaftDashed, + ArrowItem::HeadNone, ArrowItem::HeadOpen, + tr("Dependency")); +} + +void ObjectItem::addRelationStarterTool(const CustomRelation &customRelation) +{ + ArrowItem::Shaft shaft = ArrowItem::ShaftSolid; + ArrowItem::Head headStart = ArrowItem::HeadNone; + ArrowItem::Head headEnd = ArrowItem::HeadNone; + switch (customRelation.element()) { + case CustomRelation::Element::Dependency: + shaft = ArrowItem::ShaftDashed; + switch (customRelation.direction()) { + case CustomRelation::Direction::AtoB: + headEnd = ArrowItem::HeadOpen; + break; + case CustomRelation::Direction::BToA: + headStart = ArrowItem::HeadOpen; + break; + case CustomRelation::Direction::Bi: + headStart = ArrowItem::HeadOpen; + headEnd = ArrowItem::HeadOpen; + break; + } + break; + case CustomRelation::Element::Relation: + { + // TODO support custom shapes + static const QHash shaft2shaft = { + { CustomRelation::ShaftPattern::Solid, ArrowItem::ShaftSolid }, + { CustomRelation::ShaftPattern::Dash, ArrowItem::ShaftDashed }, + { CustomRelation::ShaftPattern::Dot, ArrowItem::ShaftDot }, + { CustomRelation::ShaftPattern::DashDot, ArrowItem::ShaftDashDot }, + { CustomRelation::ShaftPattern::DashDotDot, ArrowItem::ShaftDashDotDot }, + }; + static const QHash head2head = { + { CustomRelation::Head::None, ArrowItem::HeadNone }, + { CustomRelation::Head::Shape, ArrowItem::HeadNone }, + { CustomRelation::Head::Arrow, ArrowItem::HeadOpen }, + { CustomRelation::Head::Triangle, ArrowItem::HeadTriangle }, + { CustomRelation::Head::FilledTriangle, ArrowItem::HeadFilledTriangle }, + { CustomRelation::Head::Diamond, ArrowItem::HeadDiamond }, + { CustomRelation::Head::FilledDiamond, ArrowItem::HeadFilledDiamond }, + }; + shaft = shaft2shaft.value(customRelation.shaftPattern()); + headStart = head2head.value(customRelation.endA().head()); + headEnd = head2head.value(customRelation.endB().head()); + // TODO use color? + break; + } + default: + return; + } + m_relationStarter->addArrow(customRelation.id(), shaft, headStart, headEnd, + customRelation.title()); + +} + +void ObjectItem::addStandardRelationStarterTools() +{ + addRelationStarterTool(DEPENDENCY); } void ObjectItem::updateRelationStarterGeometry(const QRectF &objectRect) diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.h b/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.h index 151006d41e2..04bf6e81d01 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.h +++ b/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.h @@ -46,10 +46,12 @@ QT_END_NAMESPACE namespace qmt { +class DElement; class DObject; class DiagramSceneModel; class StereotypesItem; class CustomIconItem; +class CustomRelation; class EditableTextItem; class RectangularSelectionItem; class RelationStarter; @@ -84,9 +86,10 @@ protected: }; public: - ObjectItem(DObject *object, DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent = 0); + ObjectItem(const QString &elementType, DObject *object, DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent = 0); ~ObjectItem() override; + QString elementType() const { return m_elementType; } DObject *object() const { return m_object; } DiagramSceneModel *diagramSceneModel() const { return m_diagramSceneModel; } @@ -119,6 +122,8 @@ public: QPointF relationStartPos() const override; void relationDrawn(const QString &id, const QPointF &toScenePos, const QList &intermediatePoints) override; + virtual void relationDrawn(const QString &id, ObjectItem *targetElement, + const QList &intermediatePoints); void align(AlignType alignType, const QString &identifier) override; @@ -147,7 +152,10 @@ protected: void updateSelectionMarker(ResizeFlags resizeFlags); void updateSelectionMarkerGeometry(const QRectF &objectRect); void updateRelationStarter(); - virtual void updateRelationStarterTools(RelationStarter *relationStarter); + RelationStarter *relationStarter() const { return m_relationStarter; } + virtual void addRelationStarterTool(const QString &id); + virtual void addRelationStarterTool(const CustomRelation &customRelation); + virtual void addStandardRelationStarterTools(); void updateRelationStarterGeometry(const QRectF &objectRect); void updateAlignmentButtons(); void updateAlignmentButtonsGeometry(const QRectF &objectRect); @@ -168,6 +176,7 @@ protected: private: QSizeF minimumSize(const QSet &items) const; + QString m_elementType; DObject *m_object = 0; DiagramSceneModel *m_diagramSceneModel = 0; bool m_isSecondarySelected = false; diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp index fc8f5a4f546..f4bdec34ae4 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp +++ b/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.cpp @@ -32,7 +32,6 @@ #include "qmt/diagram_scene/parts/contextlabelitem.h" #include "qmt/diagram_scene/parts/customiconitem.h" #include "qmt/diagram_scene/parts/editabletextitem.h" -#include "qmt/diagram_scene/parts/relationstarter.h" #include "qmt/diagram_scene/parts/stereotypesitem.h" #include "qmt/infrastructure/geometryutilities.h" #include "qmt/stereotype/stereotypecontroller.h" @@ -72,7 +71,7 @@ public: }; PackageItem::PackageItem(DPackage *package, DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent) - : ObjectItem(package, diagramSceneModel, parent) + : ObjectItem(QStringLiteral("package"), package, diagramSceneModel, parent) { } @@ -135,21 +134,7 @@ void PackageItem::update() } updateSelectionMarker(m_customIcon); - - // relation starters - if (isFocusSelected()) { - if (!m_relationStarter) { - m_relationStarter = new RelationStarter(this, diagramSceneModel(), 0); - scene()->addItem(m_relationStarter); - m_relationStarter->setZValue(RELATION_STARTER_ZVALUE); - m_relationStarter->addArrow(QStringLiteral("dependency"), ArrowItem::ShaftDashed, ArrowItem::HeadOpen); - } - } else if (m_relationStarter) { - scene()->removeItem(m_relationStarter); - delete m_relationStarter; - m_relationStarter = 0; - } - + updateRelationStarter(); updateAlignmentButtons(); updateGeometry(); } @@ -326,10 +311,7 @@ void PackageItem::updateGeometry() } updateSelectionMarkerGeometry(rect); - - if (m_relationStarter) - m_relationStarter->setPos(mapToScene(QPointF(right + 8.0, top))); - + updateRelationStarterGeometry(rect); updateAlignmentButtonsGeometry(rect); updateDepth(); } diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.h b/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.h index 6d10d29b080..8ed6fc016a6 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.h +++ b/src/libs/modelinglib/qmt/diagram_scene/items/packageitem.h @@ -65,7 +65,6 @@ private: CustomIconItem *m_customIcon = 0; QGraphicsPolygonItem *m_shape = 0; ContextLabelItem *m_contextLabel = 0; - RelationStarter *m_relationStarter = 0; }; } // namespace qmt diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.cpp index 7c099186f00..b869e914bc5 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.cpp +++ b/src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.cpp @@ -38,6 +38,8 @@ #include #include +//#define DEBUG_PAINT_SHAPE + namespace qmt { class ArrowItem::GraphicsHeadItem : public QGraphicsItem @@ -110,6 +112,7 @@ public: double length = 0.0; switch (m_head) { case ArrowItem::HeadNone: + case ArrowItem::HeadCustom: break; case ArrowItem::HeadOpen: case ArrowItem::HeadTriangle: @@ -146,6 +149,7 @@ public: bool hasDiamond = false; switch (m_head) { case ArrowItem::HeadNone: + case ArrowItem::HeadCustom: break; case ArrowItem::HeadOpen: case ArrowItem::HeadTriangle: @@ -236,7 +240,6 @@ public: ArrowItem::ArrowItem(QGraphicsItem *parent) : QGraphicsItem(parent), - m_shaft(ShaftSolid), m_shaftItem(new GraphicsShaftItem(this)) { } @@ -248,9 +251,7 @@ ArrowItem::ArrowItem(const ArrowItem &rhs, QGraphicsItem *parent) m_arrowSize(rhs.m_arrowSize), m_diamondSize(rhs.m_diamondSize), m_startHead(rhs.m_startHead), - m_startHeadItem(nullptr), - m_endHead(rhs.m_endHead), - m_endHeadItem(nullptr) + m_endHead(rhs.m_endHead) { } @@ -278,14 +279,36 @@ void ArrowItem::setDiamondSize(double diamondSize) void ArrowItem::setStartHead(ArrowItem::Head head) { - if (m_startHead != head) - m_startHead = head; + m_startHead = head; +} + +void ArrowItem::setStartHead(QGraphicsItem *startHeadItem) +{ + deleteHead(&m_startHeadItem); + if (!startHeadItem) { + m_startHead = HeadNone; + } else { + QTC_ASSERT(startHeadItem->parentItem() == this, return); + m_startHead = HeadCustom; + m_startHeadItem = startHeadItem; + } } void ArrowItem::setEndHead(ArrowItem::Head head) { - if (m_endHead != head) - m_endHead = head; + m_endHead = head; +} + +void ArrowItem::setEndHead(QGraphicsItem *endHeadItem) +{ + deleteHead(&m_endHeadItem); + if (!endHeadItem) { + m_endHead = HeadNone; + } else { + QTC_ASSERT(endHeadItem->parentItem() == this, return); + m_endHead = HeadCustom; + m_endHeadItem = endHeadItem; + } } void ArrowItem::setPoints(const QList &points) @@ -359,14 +382,14 @@ QLineF ArrowItem::lastLineSegment() const double ArrowItem::startHeadLength() const { if (m_startHeadItem) - return m_startHeadItem->calcHeadLength(); + return calcHeadLength(m_startHeadItem); return 0.0; } double ArrowItem::endHeadLength() const { if (m_endHeadItem) - return m_endHeadItem->calcHeadLength(); + return calcHeadLength(m_endHeadItem); return 0.0; } @@ -383,43 +406,79 @@ void ArrowItem::updateShaft(const Style *style) QMT_ASSERT(m_shaftItem, return); QPen pen(style->linePen()); - if (m_shaft == ShaftDashed) - pen.setDashPattern(QVector() << (4.0 / pen.widthF()) << (4.0 / pen.widthF())); + switch (m_shaft) { + case ShaftSolid: + break; + case ShaftDashed: + pen.setDashPattern(QVector() + << (4.0 / pen.widthF()) << (4.0 / pen.widthF())); + break; + case ShaftDot: + pen.setDashPattern(QVector() + << (2.0 / pen.widthF()) << (2.0 / pen.widthF())); + break; + case ShaftDashDot: + pen.setDashPattern(QVector() + << (4.0 / pen.widthF()) << (2.0 / pen.widthF()) + << (2.0 / pen.widthF()) << (2.0 / pen.widthF())); + break; + case ShaftDashDotDot: + pen.setDashPattern(QVector() + << (4.0 / pen.widthF()) << (2.0 / pen.widthF()) + << (2.0 / pen.widthF()) << (2.0 / pen.widthF()) + << (2.0 / pen.widthF()) << (2.0 / pen.widthF())); + break; + } m_shaftItem->setPen(pen); } -void ArrowItem::updateHead(GraphicsHeadItem **headItem, Head head, const Style *style) +void ArrowItem::deleteHead(QGraphicsItem **headItem) { - if (head == HeadNone) { - if (*headItem) { - if ((*headItem)->scene()) - (*headItem)->scene()->removeItem(*headItem); - delete *headItem; - *headItem = 0; - } - return; + if (*headItem) { + if ((*headItem)->scene()) + (*headItem)->scene()->removeItem(*headItem); + delete *headItem; + *headItem = 0; } - if (!*headItem) - *headItem = new GraphicsHeadItem(this); - (*headItem)->setArrowSize(m_arrowSize); - (*headItem)->setDiamondSize(m_diamondSize); - (*headItem)->setHead(head); - (*headItem)->update(style); } -void ArrowItem::updateHeadGeometry(GraphicsHeadItem **headItem, const QPointF &pos, const QPointF &otherPos) +void ArrowItem::updateHead(QGraphicsItem **headItem, Head head, const Style *style) { - if (!*headItem) + if (head == HeadNone) { + deleteHead(headItem); + } else if (head == HeadCustom) { + // nothing to do + } else { + QTC_ASSERT(*headItem == 0 || dynamic_cast(*headItem) != 0, return); + GraphicsHeadItem *item; + if (!*headItem) { + item = new GraphicsHeadItem(this); + *headItem = item; + } else { + item = dynamic_cast(*headItem); + if (!item) + return; + } + item->setArrowSize(m_arrowSize); + item->setDiamondSize(m_diamondSize); + item->setHead(head); + item->update(style); + } +} + +void ArrowItem::updateHeadGeometry(QGraphicsItem *headItem, const QPointF &pos, const QPointF &otherPos) +{ + if (!headItem) return; - (*headItem)->setPos(pos); + headItem->setPos(pos); QVector2D directionVector(pos - otherPos); directionVector.normalize(); double angle = qAcos(directionVector.x()) * 180.0 / 3.1415926535; if (directionVector.y() > 0.0) angle = -angle; - (*headItem)->setRotation(-angle); + headItem->setRotation(-angle); } void ArrowItem::updateGeometry() @@ -434,8 +493,8 @@ void ArrowItem::updateGeometry() if (m_startHeadItem) { QVector2D startDirectionVector(m_points.at(1) - m_points.at(0)); startDirectionVector.normalize(); - startDirectionVector *= m_startHeadItem->calcHeadLength(); - path.moveTo(m_points.at(0) + startDirectionVector.toPointF()); + startDirectionVector *= calcHeadLength(m_startHeadItem); + path.moveTo(m_points[0] + startDirectionVector.toPointF()); } else { path.moveTo(m_points.at(0)); } @@ -446,16 +505,24 @@ void ArrowItem::updateGeometry() if (m_endHeadItem) { QVector2D endDirectionVector(m_points.at(m_points.size() - 1) - m_points.at(m_points.size() - 2)); endDirectionVector.normalize(); - endDirectionVector *= m_endHeadItem->calcHeadLength(); - path.lineTo(m_points.at(m_points.size() - 1) - endDirectionVector.toPointF()); + endDirectionVector *= calcHeadLength(m_endHeadItem); + path.lineTo(m_points[m_points.size() - 1] - endDirectionVector.toPointF()); } else { path.lineTo(m_points.at(m_points.size() - 1)); } m_shaftItem->setPath(path); - updateHeadGeometry(&m_startHeadItem, m_points.at(0), m_points.at(1)); - updateHeadGeometry(&m_endHeadItem, m_points.at(m_points.size() - 1), m_points.at(m_points.size() - 2)); + updateHeadGeometry(m_startHeadItem, m_points.at(0), m_points.at(1)); + updateHeadGeometry(m_endHeadItem, m_points.at(m_points.size() - 1), m_points.at(m_points.size() - 2)); +} + +double ArrowItem::calcHeadLength(QGraphicsItem *headItem) const +{ + // TODO use an interface + if (GraphicsHeadItem *item = dynamic_cast(headItem)) + return item->calcHeadLength(); + return 100.0; } } // namespace qmt diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.h b/src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.h index 0f4af541fc2..aaaee4e16b9 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.h +++ b/src/libs/modelinglib/qmt/diagram_scene/parts/arrowitem.h @@ -43,11 +43,15 @@ class ArrowItem : public QGraphicsItem public: enum Shaft { ShaftSolid, - ShaftDashed + ShaftDashed, + ShaftDot, + ShaftDashDot, + ShaftDashDotDot }; enum Head { HeadNone, + HeadCustom, HeadOpen, HeadTriangle, HeadFilledTriangle, @@ -65,7 +69,9 @@ public: void setArrowSize(double arrowSize); void setDiamondSize(double diamondSize); void setStartHead(Head head); + void setStartHead(QGraphicsItem *startHeadItem); void setEndHead(Head head); + void setEndHead(QGraphicsItem *endHeadItem); void setPoints(const QList &points); QRectF boundingRect() const override; @@ -82,19 +88,21 @@ public: private: void updateShaft(const Style *style); - void updateHead(GraphicsHeadItem **headItem, Head head, const Style *style); - void updateHeadGeometry(GraphicsHeadItem **headItem, const QPointF &pos, + void deleteHead(QGraphicsItem **headItem); + void updateHead(QGraphicsItem **headItem, Head head, const Style *style); + void updateHeadGeometry(QGraphicsItem *headItem, const QPointF &pos, const QPointF &otherPos); void updateGeometry(); + double calcHeadLength(QGraphicsItem *headItem) const; Shaft m_shaft = ShaftSolid; GraphicsShaftItem *m_shaftItem = nullptr; double m_arrowSize = 10.0; double m_diamondSize = 15.0; Head m_startHead = HeadNone; - GraphicsHeadItem *m_startHeadItem = nullptr; + QGraphicsItem *m_startHeadItem = nullptr; Head m_endHead = HeadNone; - GraphicsHeadItem *m_endHeadItem = nullptr; + QGraphicsItem *m_endHeadItem = nullptr; QList m_points; }; diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.cpp b/src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.cpp index 5c2ce279e64..c795394d6d5 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.cpp +++ b/src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.cpp @@ -70,16 +70,19 @@ void RelationStarter::paint(QPainter *painter, const QStyleOptionGraphicsItem *o } void RelationStarter::addArrow(const QString &id, ArrowItem::Shaft shaft, - ArrowItem::Head endHead, ArrowItem::Head startHead) + ArrowItem::Head startHead, ArrowItem::Head endHead, + const QString &toolTip) { QMT_CHECK(!id.isEmpty()); prepareGeometryChange(); auto arrow = new ArrowItem(this); arrow->setArrowSize(10.0); - arrow->setDiamondSize(15.0); + arrow->setDiamondSize(8.0); arrow->setShaft(shaft); arrow->setStartHead(startHead); arrow->setEndHead(endHead); + if (!toolTip.isEmpty()) + arrow->setToolTip(toolTip); arrow->setPoints(QList() << QPointF(0.0, 10.0) << QPointF(15.0, 0.0)); arrow->setPos(6.0, m_arrows.size() * 20.0 + 8.0); arrow->update(m_diagramSceneModel->styleController()->relationStarterStyle()); @@ -99,6 +102,9 @@ void RelationStarter::mousePressEvent(QGraphicsSceneMouseEvent *event) m_currentPreviewArrowId = m_arrowIds.value(item); QMT_CHECK(!m_currentPreviewArrowId.isEmpty()); m_currentPreviewArrow = new ArrowItem(*item); + // TODO use constants for sizes (in relationitem.h also) + m_currentPreviewArrow->setArrowSize(12.0); + m_currentPreviewArrow->setDiamondSize(12.0); m_currentPreviewArrow->setPoints(QList() << m_owner->relationStartPos() << mapToScene(event->pos())); m_currentPreviewArrow->update(m_diagramSceneModel->styleController()->relationStarterStyle()); m_currentPreviewArrow->setZValue(PREVIEW_RELATION_ZVALUE); diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.h b/src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.h index cbf69e9244f..e1244870684 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.h +++ b/src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.h @@ -47,8 +47,9 @@ public: void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) override; - void addArrow(const QString &id, ArrowItem::Shaft shaft, ArrowItem::Head endHead, - ArrowItem::Head startHead = ArrowItem::HeadNone); + void addArrow(const QString &id, ArrowItem::Shaft shaft, ArrowItem::Head startHead, + ArrowItem::Head endHead, + const QString &toolTip = QString()); protected: void mousePressEvent(QGraphicsSceneMouseEvent *event) override; diff --git a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp index 74dbfb14f7b..78297bb3122 100644 --- a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp +++ b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp @@ -36,6 +36,7 @@ #include "qmt/diagram/dpackage.h" #include "qmt/diagram/ditem.h" #include "qmt/diagram/drelation.h" +#include "qmt/diagram/dassociation.h" #include "qmt/diagram_ui/diagram_mime_types.h" #include "qmt/model_controller/modelcontroller.h" #include "qmt/model_controller/mselection.h" @@ -221,7 +222,8 @@ void DiagramSceneController::createInheritance(DClass *derivedClass, DClass *bas } void DiagramSceneController::createAssociation(DClass *endAClass, DClass *endBClass, - const QList &intermediatePoints, MDiagram *diagram) + const QList &intermediatePoints, MDiagram *diagram, + std::function custom) { m_diagramController->undoController()->beginMergeSequence(tr("Create Association")); @@ -243,6 +245,11 @@ void DiagramSceneController::createAssociation(DClass *endAClass, DClass *endBCl m_modelController->addRelation(endAModelObject, modelAssociation); DRelation *relation = addRelation(modelAssociation, intermediatePoints, diagram); + DAssociation *diagramAssociation = dynamic_cast(relation); + QMT_CHECK(diagramAssociation); + + if (custom) + custom(modelAssociation, diagramAssociation); m_diagramController->undoController()->endMergeSequence(); diff --git a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h index 967e02f51c9..855df4093e3 100644 --- a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h +++ b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h @@ -28,6 +28,8 @@ #include #include "qmt/infrastructure/qmt_global.h" +#include + QT_BEGIN_NAMESPACE class QPointF; QT_END_NAMESPACE @@ -41,10 +43,12 @@ class MObject; class MPackage; class MDiagram; class MRelation; +class MAssociation; class DElement; class DObject; class DClass; class DRelation; +class DAssociation; class DSelection; class IElementTasks; class ISceneInspector; @@ -80,7 +84,8 @@ public: void createInheritance(DClass *derivedClass, DClass *baseClass, const QList &intermediatePoints, MDiagram *diagram); void createAssociation(DClass *endAClass, DClass *endBClass, - const QList &intermediatePoints, MDiagram *diagram); + const QList &intermediatePoints, MDiagram *diagram, + std::function custom = 0); bool relocateRelationEndA(DRelation *relation, DObject *targetObject); bool relocateRelationEndB(DRelation *relation, DObject *targetObject);