ModelEditor: Show relation templates in object toolbars

Change-Id: I06de22538e500c133693ff0c791ac8a2d3be3402
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
Jochen Becher
2016-08-20 21:46:55 +02:00
parent 6ea47c98fb
commit 82cb2b248e
19 changed files with 464 additions and 159 deletions

View File

@@ -38,6 +38,7 @@
#include "qmt/diagram/drelation.h" #include "qmt/diagram/drelation.h"
#include "qmt/diagram_controller/diagramcontroller.h" #include "qmt/diagram_controller/diagramcontroller.h"
#include "qmt/diagram_controller/dselection.h" #include "qmt/diagram_controller/dselection.h"
#include "qmt/diagram_scene/items/objectitem.h"
#include "qmt/model/mdiagram.h" #include "qmt/model/mdiagram.h"
#include "qmt/model/mobject.h" #include "qmt/model/mobject.h"
#include "qmt/model/mpackage.h" #include "qmt/model/mpackage.h"
@@ -229,17 +230,25 @@ DElement *DiagramSceneModel::findTopmostElement(const QPointF &scenePos) const
} }
DObject *DiagramSceneModel::findTopmostObject(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 // fetch affected items from scene in correct drawing order to find topmost element
QList<QGraphicsItem *> items = m_graphicsScene->items(scenePos); const QList<QGraphicsItem *> items = m_graphicsScene->items(scenePos);
foreach (QGraphicsItem *item, items) { for (QGraphicsItem *item : items) {
if (m_graphicsItems.contains(item)) { if (m_graphicsItems.contains(item)) {
DObject *object = dynamic_cast<DObject *>(m_itemToElementMap.value(item)); DObject *object = dynamic_cast<DObject *>(m_itemToElementMap.value(item));
if (object) if (object)
return object; return dynamic_cast<ObjectItem *>(item);
} }
} }
return 0; return nullptr;
} }
QGraphicsItem *DiagramSceneModel::graphicsItem(DElement *element) const QGraphicsItem *DiagramSceneModel::graphicsItem(DElement *element) const

View File

@@ -54,6 +54,7 @@ class DSelection;
class MDiagram; class MDiagram;
class DElement; class DElement;
class DObject; class DObject;
class ObjectItem;
class QMT_EXPORT DiagramSceneModel : public QObject class QMT_EXPORT DiagramSceneModel : public QObject
{ {
@@ -98,6 +99,7 @@ public:
DSelection selectedElements() const; DSelection selectedElements() const;
DElement *findTopmostElement(const QPointF &scenePos) const; DElement *findTopmostElement(const QPointF &scenePos) const;
DObject *findTopmostObject(const QPointF &scenePos) const; DObject *findTopmostObject(const QPointF &scenePos) const;
ObjectItem *findTopmostObjectItem(const QPointF &scenePos) const;
QList<QGraphicsItem *> graphicsItems() const { return m_graphicsItems; } QList<QGraphicsItem *> graphicsItems() const { return m_graphicsItems; }
QGraphicsItem *graphicsItem(DElement *element) const; QGraphicsItem *graphicsItem(DElement *element) const;

View File

@@ -40,6 +40,7 @@
#include "qmt/infrastructure/qmtassert.h" #include "qmt/infrastructure/qmtassert.h"
#include "qmt/model/mclass.h" #include "qmt/model/mclass.h"
#include "qmt/model/mclassmember.h" #include "qmt/model/mclassmember.h"
#include "qmt/model/massociation.h"
#include "qmt/model_controller/modelcontroller.h" #include "qmt/model_controller/modelcontroller.h"
#include "qmt/stereotype/stereotypecontroller.h" #include "qmt/stereotype/stereotypecontroller.h"
#include "qmt/stereotype/stereotypeicon.h" #include "qmt/stereotype/stereotypeicon.h"
@@ -59,15 +60,20 @@
#include <algorithm> #include <algorithm>
#include <qmt/stereotype/customrelation.h>
namespace qmt { 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_WIDTH = 80.0;
static const qreal MINIMUM_AUTO_HEIGHT = 60.0; static const qreal MINIMUM_AUTO_HEIGHT = 60.0;
static const qreal BODY_VERT_BORDER = 4.0; static const qreal BODY_VERT_BORDER = 4.0;
static const qreal BODY_HORIZ_BORDER = 4.0; static const qreal BODY_HORIZ_BORDER = 4.0;
ClassItem::ClassItem(DClass *klass, DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent) 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(); return calcMinimumGeometry();
} }
void ClassItem::relationDrawn(const QString &id, const QPointF &toScenePos, const QList<QPointF> &intermediatePoints) void ClassItem::relationDrawn(const QString &id, ObjectItem *targetItem, const QList<QPointF> &intermediatePoints)
{ {
DElement *targetElement = diagramSceneModel()->findTopmostElement(toScenePos); DiagramSceneController *diagramSceneController = diagramSceneModel()->diagramSceneController();
if (targetElement) { if (id == INHERITANCE) {
if (id == QLatin1String("inheritance")) { auto baseClass = dynamic_cast<DClass *>(targetItem->object());
auto baseClass = dynamic_cast<DClass *>(targetElement); if (baseClass) {
if (baseClass) { auto derivedClass = dynamic_cast<DClass *>(object());
auto derivedClass = dynamic_cast<DClass *>(object()); QMT_ASSERT(derivedClass, return);
QMT_ASSERT(derivedClass, return); diagramSceneController->createInheritance(derivedClass, baseClass, intermediatePoints, diagramSceneModel()->diagram());
diagramSceneModel()->diagramSceneController()->createInheritance(derivedClass, baseClass, intermediatePoints, diagramSceneModel()->diagram()); }
return;
} else if (id == ASSOCIATION) {
auto associatedClass = dynamic_cast<DClass *>(targetItem->object());
if (associatedClass) {
auto derivedClass = dynamic_cast<DClass *>(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<DClass *>(targetItem->object());
if (baseClass) {
auto derivedClass = dynamic_cast<DClass *>(object());
QMT_ASSERT(derivedClass, return);
diagramSceneController->createInheritance(derivedClass, baseClass, intermediatePoints, diagramSceneModel()->diagram());
}
return;
} }
} else if (id == QLatin1String("dependency")) { case CustomRelation::Element::Association:
auto dependantObject = dynamic_cast<DObject *>(targetElement); {
if (dependantObject) auto assoziatedClass = dynamic_cast<DClass *>(targetItem->object());
diagramSceneModel()->diagramSceneController()->createDependency(object(), dependantObject, intermediatePoints, diagramSceneModel()->diagram()); if (assoziatedClass) {
} else if (id == QLatin1String("association")) { auto derivedClass = dynamic_cast<DClass *>(object());
auto assoziatedClass = dynamic_cast<DClass *>(targetElement); QMT_ASSERT(derivedClass, return);
if (assoziatedClass) { diagramSceneController->createAssociation(
auto derivedClass = dynamic_cast<DClass *>(object()); derivedClass, assoziatedClass, intermediatePoints, diagramSceneModel()->diagram(),
QMT_ASSERT(derivedClass, return); [=] (MAssociation *mAssociation, DAssociation *dAssociation) {
diagramSceneModel()->diagramSceneController()->createAssociation(derivedClass, assoziatedClass, intermediatePoints, diagramSceneModel()->diagram()); if (mAssociation && dAssociation) {
static const QHash<CustomRelation::Relationship, MAssociationEnd::Kind> 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) 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); if (id == INHERITANCE)
relationStarter->addArrow("inheritance", ArrowItem::ShaftSolid, ArrowItem::HeadTriangle); relationStarter()->addArrow(INHERITANCE, ArrowItem::ShaftSolid,
relationStarter->addArrow("association", ArrowItem::ShaftSolid, ArrowItem::HeadFilledTriangle); 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 DClass::TemplateDisplay ClassItem::templateDisplay() const

View File

@@ -59,7 +59,7 @@ public:
QSizeF minimumSize() const override; QSizeF minimumSize() const override;
void relationDrawn(const QString &id, const QPointF &toScenePos, void relationDrawn(const QString &id, ObjectItem *targetElement,
const QList<QPointF> &intermediatePoints) override; const QList<QPointF> &intermediatePoints) override;
protected: protected:
@@ -67,7 +67,9 @@ protected:
bool handleSelectedContextMenuAction(const QString &id) override; bool handleSelectedContextMenuAction(const QString &id) override;
QString buildDisplayName() const override; QString buildDisplayName() const override;
void setFromDisplayName(const QString &displayName) 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: private:
DClass::TemplateDisplay templateDisplay() const; DClass::TemplateDisplay templateDisplay() const;

View File

@@ -32,7 +32,6 @@
#include "qmt/diagram_scene/parts/contextlabelitem.h" #include "qmt/diagram_scene/parts/contextlabelitem.h"
#include "qmt/diagram_scene/parts/customiconitem.h" #include "qmt/diagram_scene/parts/customiconitem.h"
#include "qmt/diagram_scene/parts/editabletextitem.h" #include "qmt/diagram_scene/parts/editabletextitem.h"
#include "qmt/diagram_scene/parts/relationstarter.h"
#include "qmt/diagram_scene/parts/stereotypesitem.h" #include "qmt/diagram_scene/parts/stereotypesitem.h"
#include "qmt/infrastructure/geometryutilities.h" #include "qmt/infrastructure/geometryutilities.h"
#include "qmt/infrastructure/qmtassert.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; static const qreal BODY_HORIZ_BORDER = 4.0;
ComponentItem::ComponentItem(DComponent *component, DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent) 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); updateSelectionMarker(m_customIcon);
updateRelationStarter();
// 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;
}
updateAlignmentButtons(); updateAlignmentButtons();
updateGeometry(); updateGeometry();
} }
@@ -344,10 +328,7 @@ void ComponentItem::updateGeometry()
} }
updateSelectionMarkerGeometry(rect); updateSelectionMarkerGeometry(rect);
updateRelationStarterGeometry(rect);
if (m_relationStarter)
m_relationStarter->setPos(mapToScene(QPointF(right + 8.0, top)));
updateAlignmentButtonsGeometry(rect); updateAlignmentButtonsGeometry(rect);
updateDepth(); updateDepth();
} }

View File

@@ -68,7 +68,6 @@ private:
QGraphicsRectItem *m_upperRect = 0; QGraphicsRectItem *m_upperRect = 0;
QGraphicsRectItem *m_lowerRect = 0; QGraphicsRectItem *m_lowerRect = 0;
ContextLabelItem *m_contextLabel = 0; ContextLabelItem *m_contextLabel = 0;
RelationStarter *m_relationStarter = 0;
}; };
} // namespace qmt } // namespace qmt

View File

@@ -54,7 +54,7 @@ static const qreal BODY_HORIZ_BORDER = 4.0;
static const qreal BODY_VERT_BORDER = 4.0; static const qreal BODY_VERT_BORDER = 4.0;
DiagramItem::DiagramItem(DDiagram *diagram, DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent) DiagramItem::DiagramItem(DDiagram *diagram, DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent)
: ObjectItem(diagram, diagramSceneModel, parent) : ObjectItem(QStringLiteral("diagram"), diagram, diagramSceneModel, parent)
{ {
} }

View File

@@ -32,7 +32,6 @@
#include "qmt/diagram_scene/parts/contextlabelitem.h" #include "qmt/diagram_scene/parts/contextlabelitem.h"
#include "qmt/diagram_scene/parts/customiconitem.h" #include "qmt/diagram_scene/parts/customiconitem.h"
#include "qmt/diagram_scene/parts/editabletextitem.h" #include "qmt/diagram_scene/parts/editabletextitem.h"
#include "qmt/diagram_scene/parts/relationstarter.h"
#include "qmt/diagram_scene/parts/stereotypesitem.h" #include "qmt/diagram_scene/parts/stereotypesitem.h"
#include "qmt/infrastructure/geometryutilities.h" #include "qmt/infrastructure/geometryutilities.h"
#include "qmt/infrastructure/qmtassert.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; static const qreal BODY_HORIZ_BORDER = 4.0;
ItemItem::ItemItem(DItem *item, DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent) 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); updateSelectionMarker(m_customIcon);
updateRelationStarter();
// 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;
}
updateAlignmentButtons(); updateAlignmentButtons();
updateGeometry(); updateGeometry();
} }
@@ -277,10 +261,7 @@ void ItemItem::updateGeometry()
} }
updateSelectionMarkerGeometry(rect); updateSelectionMarkerGeometry(rect);
updateRelationStarterGeometry(rect);
if (m_relationStarter)
m_relationStarter->setPos(mapToScene(QPointF(right + 8.0, top)));
updateAlignmentButtonsGeometry(rect); updateAlignmentButtonsGeometry(rect);
updateDepth(); updateDepth();
} }

View File

@@ -64,7 +64,6 @@ private:
CustomIconItem *m_customIcon = 0; CustomIconItem *m_customIcon = 0;
QGraphicsRectItem *m_shape = 0; QGraphicsRectItem *m_shape = 0;
ContextLabelItem *m_contextLabel = 0; ContextLabelItem *m_contextLabel = 0;
RelationStarter *m_relationStarter = 0;
}; };
} // namespace qmt } // namespace qmt

View File

@@ -42,7 +42,9 @@
#include "qmt/model/mdiagram.h" #include "qmt/model/mdiagram.h"
#include "qmt/model/mobject.h" #include "qmt/model/mobject.h"
#include "qmt/model_controller/modelcontroller.h" #include "qmt/model_controller/modelcontroller.h"
#include "qmt/stereotype/customrelation.h"
#include "qmt/stereotype/stereotypecontroller.h" #include "qmt/stereotype/stereotypecontroller.h"
#include "qmt/stereotype/toolbar.h"
#include "qmt/style/style.h" #include "qmt/style/style.h"
#include "qmt/style/stylecontroller.h" #include "qmt/style/stylecontroller.h"
#include "qmt/style/styledobject.h" #include "qmt/style/styledobject.h"
@@ -58,8 +60,12 @@
namespace qmt { 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), : QGraphicsItem(parent),
m_elementType(elementType),
m_object(object), m_object(object),
m_diagramSceneModel(diagramSceneModel) m_diagramSceneModel(diagramSceneModel)
{ {
@@ -309,12 +315,58 @@ QPointF ObjectItem::relationStartPos() const
void ObjectItem::relationDrawn(const QString &id, const QPointF &toScenePos, const QList<QPointF> &intermediatePoints) void ObjectItem::relationDrawn(const QString &id, const QPointF &toScenePos, const QList<QPointF> &intermediatePoints)
{ {
DElement *targetElement = diagramSceneModel()->findTopmostElement(toScenePos); ObjectItem *targetItem = diagramSceneModel()->findTopmostObjectItem(toScenePos);
if (targetElement) { if (targetItem)
if (id == QLatin1String("dependency")) { relationDrawn(id, targetItem, intermediatePoints);
auto dependantObject = dynamic_cast<DObject *>(targetElement); }
if (dependantObject)
diagramSceneModel()->diagramSceneController()->createDependency(object(), dependantObject, intermediatePoints, diagramSceneModel()->diagram()); void ObjectItem::relationDrawn(const QString &id, ObjectItem *targetItem, const QList<QPointF> &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<QString> 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); m_relationStarter = new RelationStarter(this, diagramSceneModel(), 0);
scene()->addItem(m_relationStarter); scene()->addItem(m_relationStarter);
m_relationStarter->setZValue(RELATION_STARTER_ZVALUE); 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<Toolbar> 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) { } else if (m_relationStarter) {
scene()->removeItem(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<CustomRelation::ShaftPattern, ArrowItem::Shaft> 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<CustomRelation::Head, ArrowItem::Head> 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) void ObjectItem::updateRelationStarterGeometry(const QRectF &objectRect)

View File

@@ -46,10 +46,12 @@ QT_END_NAMESPACE
namespace qmt { namespace qmt {
class DElement;
class DObject; class DObject;
class DiagramSceneModel; class DiagramSceneModel;
class StereotypesItem; class StereotypesItem;
class CustomIconItem; class CustomIconItem;
class CustomRelation;
class EditableTextItem; class EditableTextItem;
class RectangularSelectionItem; class RectangularSelectionItem;
class RelationStarter; class RelationStarter;
@@ -84,9 +86,10 @@ protected:
}; };
public: public:
ObjectItem(DObject *object, DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent = 0); ObjectItem(const QString &elementType, DObject *object, DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent = 0);
~ObjectItem() override; ~ObjectItem() override;
QString elementType() const { return m_elementType; }
DObject *object() const { return m_object; } DObject *object() const { return m_object; }
DiagramSceneModel *diagramSceneModel() const { return m_diagramSceneModel; } DiagramSceneModel *diagramSceneModel() const { return m_diagramSceneModel; }
@@ -119,6 +122,8 @@ public:
QPointF relationStartPos() const override; QPointF relationStartPos() const override;
void relationDrawn(const QString &id, const QPointF &toScenePos, void relationDrawn(const QString &id, const QPointF &toScenePos,
const QList<QPointF> &intermediatePoints) override; const QList<QPointF> &intermediatePoints) override;
virtual void relationDrawn(const QString &id, ObjectItem *targetElement,
const QList<QPointF> &intermediatePoints);
void align(AlignType alignType, const QString &identifier) override; void align(AlignType alignType, const QString &identifier) override;
@@ -147,7 +152,10 @@ protected:
void updateSelectionMarker(ResizeFlags resizeFlags); void updateSelectionMarker(ResizeFlags resizeFlags);
void updateSelectionMarkerGeometry(const QRectF &objectRect); void updateSelectionMarkerGeometry(const QRectF &objectRect);
void updateRelationStarter(); 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 updateRelationStarterGeometry(const QRectF &objectRect);
void updateAlignmentButtons(); void updateAlignmentButtons();
void updateAlignmentButtonsGeometry(const QRectF &objectRect); void updateAlignmentButtonsGeometry(const QRectF &objectRect);
@@ -168,6 +176,7 @@ protected:
private: private:
QSizeF minimumSize(const QSet<QGraphicsItem *> &items) const; QSizeF minimumSize(const QSet<QGraphicsItem *> &items) const;
QString m_elementType;
DObject *m_object = 0; DObject *m_object = 0;
DiagramSceneModel *m_diagramSceneModel = 0; DiagramSceneModel *m_diagramSceneModel = 0;
bool m_isSecondarySelected = false; bool m_isSecondarySelected = false;

View File

@@ -32,7 +32,6 @@
#include "qmt/diagram_scene/parts/contextlabelitem.h" #include "qmt/diagram_scene/parts/contextlabelitem.h"
#include "qmt/diagram_scene/parts/customiconitem.h" #include "qmt/diagram_scene/parts/customiconitem.h"
#include "qmt/diagram_scene/parts/editabletextitem.h" #include "qmt/diagram_scene/parts/editabletextitem.h"
#include "qmt/diagram_scene/parts/relationstarter.h"
#include "qmt/diagram_scene/parts/stereotypesitem.h" #include "qmt/diagram_scene/parts/stereotypesitem.h"
#include "qmt/infrastructure/geometryutilities.h" #include "qmt/infrastructure/geometryutilities.h"
#include "qmt/stereotype/stereotypecontroller.h" #include "qmt/stereotype/stereotypecontroller.h"
@@ -72,7 +71,7 @@ public:
}; };
PackageItem::PackageItem(DPackage *package, DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent) 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); updateSelectionMarker(m_customIcon);
updateRelationStarter();
// 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;
}
updateAlignmentButtons(); updateAlignmentButtons();
updateGeometry(); updateGeometry();
} }
@@ -326,10 +311,7 @@ void PackageItem::updateGeometry()
} }
updateSelectionMarkerGeometry(rect); updateSelectionMarkerGeometry(rect);
updateRelationStarterGeometry(rect);
if (m_relationStarter)
m_relationStarter->setPos(mapToScene(QPointF(right + 8.0, top)));
updateAlignmentButtonsGeometry(rect); updateAlignmentButtonsGeometry(rect);
updateDepth(); updateDepth();
} }

View File

@@ -65,7 +65,6 @@ private:
CustomIconItem *m_customIcon = 0; CustomIconItem *m_customIcon = 0;
QGraphicsPolygonItem *m_shape = 0; QGraphicsPolygonItem *m_shape = 0;
ContextLabelItem *m_contextLabel = 0; ContextLabelItem *m_contextLabel = 0;
RelationStarter *m_relationStarter = 0;
}; };
} // namespace qmt } // namespace qmt

View File

@@ -38,6 +38,8 @@
#include <QPainter> #include <QPainter>
#include <QPen> #include <QPen>
//#define DEBUG_PAINT_SHAPE
namespace qmt { namespace qmt {
class ArrowItem::GraphicsHeadItem : public QGraphicsItem class ArrowItem::GraphicsHeadItem : public QGraphicsItem
@@ -110,6 +112,7 @@ public:
double length = 0.0; double length = 0.0;
switch (m_head) { switch (m_head) {
case ArrowItem::HeadNone: case ArrowItem::HeadNone:
case ArrowItem::HeadCustom:
break; break;
case ArrowItem::HeadOpen: case ArrowItem::HeadOpen:
case ArrowItem::HeadTriangle: case ArrowItem::HeadTriangle:
@@ -146,6 +149,7 @@ public:
bool hasDiamond = false; bool hasDiamond = false;
switch (m_head) { switch (m_head) {
case ArrowItem::HeadNone: case ArrowItem::HeadNone:
case ArrowItem::HeadCustom:
break; break;
case ArrowItem::HeadOpen: case ArrowItem::HeadOpen:
case ArrowItem::HeadTriangle: case ArrowItem::HeadTriangle:
@@ -236,7 +240,6 @@ public:
ArrowItem::ArrowItem(QGraphicsItem *parent) ArrowItem::ArrowItem(QGraphicsItem *parent)
: QGraphicsItem(parent), : QGraphicsItem(parent),
m_shaft(ShaftSolid),
m_shaftItem(new GraphicsShaftItem(this)) m_shaftItem(new GraphicsShaftItem(this))
{ {
} }
@@ -248,9 +251,7 @@ ArrowItem::ArrowItem(const ArrowItem &rhs, QGraphicsItem *parent)
m_arrowSize(rhs.m_arrowSize), m_arrowSize(rhs.m_arrowSize),
m_diamondSize(rhs.m_diamondSize), m_diamondSize(rhs.m_diamondSize),
m_startHead(rhs.m_startHead), m_startHead(rhs.m_startHead),
m_startHeadItem(nullptr), m_endHead(rhs.m_endHead)
m_endHead(rhs.m_endHead),
m_endHeadItem(nullptr)
{ {
} }
@@ -278,14 +279,36 @@ void ArrowItem::setDiamondSize(double diamondSize)
void ArrowItem::setStartHead(ArrowItem::Head head) 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) 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<QPointF> &points) void ArrowItem::setPoints(const QList<QPointF> &points)
@@ -359,14 +382,14 @@ QLineF ArrowItem::lastLineSegment() const
double ArrowItem::startHeadLength() const double ArrowItem::startHeadLength() const
{ {
if (m_startHeadItem) if (m_startHeadItem)
return m_startHeadItem->calcHeadLength(); return calcHeadLength(m_startHeadItem);
return 0.0; return 0.0;
} }
double ArrowItem::endHeadLength() const double ArrowItem::endHeadLength() const
{ {
if (m_endHeadItem) if (m_endHeadItem)
return m_endHeadItem->calcHeadLength(); return calcHeadLength(m_endHeadItem);
return 0.0; return 0.0;
} }
@@ -383,43 +406,79 @@ void ArrowItem::updateShaft(const Style *style)
QMT_ASSERT(m_shaftItem, return); QMT_ASSERT(m_shaftItem, return);
QPen pen(style->linePen()); QPen pen(style->linePen());
if (m_shaft == ShaftDashed) switch (m_shaft) {
pen.setDashPattern(QVector<qreal>() << (4.0 / pen.widthF()) << (4.0 / pen.widthF())); case ShaftSolid:
break;
case ShaftDashed:
pen.setDashPattern(QVector<qreal>()
<< (4.0 / pen.widthF()) << (4.0 / pen.widthF()));
break;
case ShaftDot:
pen.setDashPattern(QVector<qreal>()
<< (2.0 / pen.widthF()) << (2.0 / pen.widthF()));
break;
case ShaftDashDot:
pen.setDashPattern(QVector<qreal>()
<< (4.0 / pen.widthF()) << (2.0 / pen.widthF())
<< (2.0 / pen.widthF()) << (2.0 / pen.widthF()));
break;
case ShaftDashDotDot:
pen.setDashPattern(QVector<qreal>()
<< (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); 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) { if ((*headItem)->scene())
if ((*headItem)->scene()) (*headItem)->scene()->removeItem(*headItem);
(*headItem)->scene()->removeItem(*headItem); delete *headItem;
delete *headItem; *headItem = 0;
*headItem = 0;
}
return;
} }
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<GraphicsHeadItem *>(*headItem) != 0, return);
GraphicsHeadItem *item;
if (!*headItem) {
item = new GraphicsHeadItem(this);
*headItem = item;
} else {
item = dynamic_cast<GraphicsHeadItem *>(*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; return;
(*headItem)->setPos(pos); headItem->setPos(pos);
QVector2D directionVector(pos - otherPos); QVector2D directionVector(pos - otherPos);
directionVector.normalize(); directionVector.normalize();
double angle = qAcos(directionVector.x()) * 180.0 / 3.1415926535; double angle = qAcos(directionVector.x()) * 180.0 / 3.1415926535;
if (directionVector.y() > 0.0) if (directionVector.y() > 0.0)
angle = -angle; angle = -angle;
(*headItem)->setRotation(-angle); headItem->setRotation(-angle);
} }
void ArrowItem::updateGeometry() void ArrowItem::updateGeometry()
@@ -434,8 +493,8 @@ void ArrowItem::updateGeometry()
if (m_startHeadItem) { if (m_startHeadItem) {
QVector2D startDirectionVector(m_points.at(1) - m_points.at(0)); QVector2D startDirectionVector(m_points.at(1) - m_points.at(0));
startDirectionVector.normalize(); startDirectionVector.normalize();
startDirectionVector *= m_startHeadItem->calcHeadLength(); startDirectionVector *= calcHeadLength(m_startHeadItem);
path.moveTo(m_points.at(0) + startDirectionVector.toPointF()); path.moveTo(m_points[0] + startDirectionVector.toPointF());
} else { } else {
path.moveTo(m_points.at(0)); path.moveTo(m_points.at(0));
} }
@@ -446,16 +505,24 @@ void ArrowItem::updateGeometry()
if (m_endHeadItem) { if (m_endHeadItem) {
QVector2D endDirectionVector(m_points.at(m_points.size() - 1) - m_points.at(m_points.size() - 2)); QVector2D endDirectionVector(m_points.at(m_points.size() - 1) - m_points.at(m_points.size() - 2));
endDirectionVector.normalize(); endDirectionVector.normalize();
endDirectionVector *= m_endHeadItem->calcHeadLength(); endDirectionVector *= calcHeadLength(m_endHeadItem);
path.lineTo(m_points.at(m_points.size() - 1) - endDirectionVector.toPointF()); path.lineTo(m_points[m_points.size() - 1] - endDirectionVector.toPointF());
} else { } else {
path.lineTo(m_points.at(m_points.size() - 1)); path.lineTo(m_points.at(m_points.size() - 1));
} }
m_shaftItem->setPath(path); m_shaftItem->setPath(path);
updateHeadGeometry(&m_startHeadItem, m_points.at(0), m_points.at(1)); 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_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<GraphicsHeadItem *>(headItem))
return item->calcHeadLength();
return 100.0;
} }
} // namespace qmt } // namespace qmt

View File

@@ -43,11 +43,15 @@ class ArrowItem : public QGraphicsItem
public: public:
enum Shaft { enum Shaft {
ShaftSolid, ShaftSolid,
ShaftDashed ShaftDashed,
ShaftDot,
ShaftDashDot,
ShaftDashDotDot
}; };
enum Head { enum Head {
HeadNone, HeadNone,
HeadCustom,
HeadOpen, HeadOpen,
HeadTriangle, HeadTriangle,
HeadFilledTriangle, HeadFilledTriangle,
@@ -65,7 +69,9 @@ public:
void setArrowSize(double arrowSize); void setArrowSize(double arrowSize);
void setDiamondSize(double diamondSize); void setDiamondSize(double diamondSize);
void setStartHead(Head head); void setStartHead(Head head);
void setStartHead(QGraphicsItem *startHeadItem);
void setEndHead(Head head); void setEndHead(Head head);
void setEndHead(QGraphicsItem *endHeadItem);
void setPoints(const QList<QPointF> &points); void setPoints(const QList<QPointF> &points);
QRectF boundingRect() const override; QRectF boundingRect() const override;
@@ -82,19 +88,21 @@ public:
private: private:
void updateShaft(const Style *style); void updateShaft(const Style *style);
void updateHead(GraphicsHeadItem **headItem, Head head, const Style *style); void deleteHead(QGraphicsItem **headItem);
void updateHeadGeometry(GraphicsHeadItem **headItem, const QPointF &pos, void updateHead(QGraphicsItem **headItem, Head head, const Style *style);
void updateHeadGeometry(QGraphicsItem *headItem, const QPointF &pos,
const QPointF &otherPos); const QPointF &otherPos);
void updateGeometry(); void updateGeometry();
double calcHeadLength(QGraphicsItem *headItem) const;
Shaft m_shaft = ShaftSolid; Shaft m_shaft = ShaftSolid;
GraphicsShaftItem *m_shaftItem = nullptr; GraphicsShaftItem *m_shaftItem = nullptr;
double m_arrowSize = 10.0; double m_arrowSize = 10.0;
double m_diamondSize = 15.0; double m_diamondSize = 15.0;
Head m_startHead = HeadNone; Head m_startHead = HeadNone;
GraphicsHeadItem *m_startHeadItem = nullptr; QGraphicsItem *m_startHeadItem = nullptr;
Head m_endHead = HeadNone; Head m_endHead = HeadNone;
GraphicsHeadItem *m_endHeadItem = nullptr; QGraphicsItem *m_endHeadItem = nullptr;
QList<QPointF> m_points; QList<QPointF> m_points;
}; };

View File

@@ -70,16 +70,19 @@ void RelationStarter::paint(QPainter *painter, const QStyleOptionGraphicsItem *o
} }
void RelationStarter::addArrow(const QString &id, ArrowItem::Shaft shaft, 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()); QMT_CHECK(!id.isEmpty());
prepareGeometryChange(); prepareGeometryChange();
auto arrow = new ArrowItem(this); auto arrow = new ArrowItem(this);
arrow->setArrowSize(10.0); arrow->setArrowSize(10.0);
arrow->setDiamondSize(15.0); arrow->setDiamondSize(8.0);
arrow->setShaft(shaft); arrow->setShaft(shaft);
arrow->setStartHead(startHead); arrow->setStartHead(startHead);
arrow->setEndHead(endHead); arrow->setEndHead(endHead);
if (!toolTip.isEmpty())
arrow->setToolTip(toolTip);
arrow->setPoints(QList<QPointF>() << QPointF(0.0, 10.0) << QPointF(15.0, 0.0)); arrow->setPoints(QList<QPointF>() << QPointF(0.0, 10.0) << QPointF(15.0, 0.0));
arrow->setPos(6.0, m_arrows.size() * 20.0 + 8.0); arrow->setPos(6.0, m_arrows.size() * 20.0 + 8.0);
arrow->update(m_diagramSceneModel->styleController()->relationStarterStyle()); arrow->update(m_diagramSceneModel->styleController()->relationStarterStyle());
@@ -99,6 +102,9 @@ void RelationStarter::mousePressEvent(QGraphicsSceneMouseEvent *event)
m_currentPreviewArrowId = m_arrowIds.value(item); m_currentPreviewArrowId = m_arrowIds.value(item);
QMT_CHECK(!m_currentPreviewArrowId.isEmpty()); QMT_CHECK(!m_currentPreviewArrowId.isEmpty());
m_currentPreviewArrow = new ArrowItem(*item); 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<QPointF>() << m_owner->relationStartPos() << mapToScene(event->pos())); m_currentPreviewArrow->setPoints(QList<QPointF>() << m_owner->relationStartPos() << mapToScene(event->pos()));
m_currentPreviewArrow->update(m_diagramSceneModel->styleController()->relationStarterStyle()); m_currentPreviewArrow->update(m_diagramSceneModel->styleController()->relationStarterStyle());
m_currentPreviewArrow->setZValue(PREVIEW_RELATION_ZVALUE); m_currentPreviewArrow->setZValue(PREVIEW_RELATION_ZVALUE);

View File

@@ -47,8 +47,9 @@ public:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget = 0) override; QWidget *widget = 0) override;
void addArrow(const QString &id, ArrowItem::Shaft shaft, ArrowItem::Head endHead, void addArrow(const QString &id, ArrowItem::Shaft shaft, ArrowItem::Head startHead,
ArrowItem::Head startHead = ArrowItem::HeadNone); ArrowItem::Head endHead,
const QString &toolTip = QString());
protected: protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event) override; void mousePressEvent(QGraphicsSceneMouseEvent *event) override;

View File

@@ -36,6 +36,7 @@
#include "qmt/diagram/dpackage.h" #include "qmt/diagram/dpackage.h"
#include "qmt/diagram/ditem.h" #include "qmt/diagram/ditem.h"
#include "qmt/diagram/drelation.h" #include "qmt/diagram/drelation.h"
#include "qmt/diagram/dassociation.h"
#include "qmt/diagram_ui/diagram_mime_types.h" #include "qmt/diagram_ui/diagram_mime_types.h"
#include "qmt/model_controller/modelcontroller.h" #include "qmt/model_controller/modelcontroller.h"
#include "qmt/model_controller/mselection.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, void DiagramSceneController::createAssociation(DClass *endAClass, DClass *endBClass,
const QList<QPointF> &intermediatePoints, MDiagram *diagram) const QList<QPointF> &intermediatePoints, MDiagram *diagram,
std::function<void (MAssociation*, DAssociation*)> custom)
{ {
m_diagramController->undoController()->beginMergeSequence(tr("Create Association")); m_diagramController->undoController()->beginMergeSequence(tr("Create Association"));
@@ -243,6 +245,11 @@ void DiagramSceneController::createAssociation(DClass *endAClass, DClass *endBCl
m_modelController->addRelation(endAModelObject, modelAssociation); m_modelController->addRelation(endAModelObject, modelAssociation);
DRelation *relation = addRelation(modelAssociation, intermediatePoints, diagram); DRelation *relation = addRelation(modelAssociation, intermediatePoints, diagram);
DAssociation *diagramAssociation = dynamic_cast<DAssociation *>(relation);
QMT_CHECK(diagramAssociation);
if (custom)
custom(modelAssociation, diagramAssociation);
m_diagramController->undoController()->endMergeSequence(); m_diagramController->undoController()->endMergeSequence();

View File

@@ -28,6 +28,8 @@
#include <QObject> #include <QObject>
#include "qmt/infrastructure/qmt_global.h" #include "qmt/infrastructure/qmt_global.h"
#include <functional>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QPointF; class QPointF;
QT_END_NAMESPACE QT_END_NAMESPACE
@@ -41,10 +43,12 @@ class MObject;
class MPackage; class MPackage;
class MDiagram; class MDiagram;
class MRelation; class MRelation;
class MAssociation;
class DElement; class DElement;
class DObject; class DObject;
class DClass; class DClass;
class DRelation; class DRelation;
class DAssociation;
class DSelection; class DSelection;
class IElementTasks; class IElementTasks;
class ISceneInspector; class ISceneInspector;
@@ -80,7 +84,8 @@ public:
void createInheritance(DClass *derivedClass, DClass *baseClass, void createInheritance(DClass *derivedClass, DClass *baseClass,
const QList<QPointF> &intermediatePoints, MDiagram *diagram); const QList<QPointF> &intermediatePoints, MDiagram *diagram);
void createAssociation(DClass *endAClass, DClass *endBClass, void createAssociation(DClass *endAClass, DClass *endBClass,
const QList<QPointF> &intermediatePoints, MDiagram *diagram); const QList<QPointF> &intermediatePoints, MDiagram *diagram,
std::function<void (MAssociation*, DAssociation*)> custom = 0);
bool relocateRelationEndA(DRelation *relation, DObject *targetObject); bool relocateRelationEndA(DRelation *relation, DObject *targetObject);
bool relocateRelationEndB(DRelation *relation, DObject *targetObject); bool relocateRelationEndB(DRelation *relation, DObject *targetObject);