From ffb5dc756a8244fb31674d674eeb59aa51b7cbe2 Mon Sep 17 00:00:00 2001 From: Jochen Becher Date: Tue, 23 Aug 2016 21:47:12 +0200 Subject: [PATCH] ModelEditor: Introduce custom relation type "Connection" Change-Id: Iddd45508dcb2de1fa2b6d9b2b881b54a73172caf Reviewed-by: Tobias Hunger --- share/qtcreator/modeleditor/standard.def | 53 ++-- src/libs/modelinglib/modelinglib.qbs | 6 + .../modelinglib/qmt/diagram/dconnection.cpp | 103 +++++++ .../modelinglib/qmt/diagram/dconnection.h | 78 +++++ .../modelinglib/qmt/diagram/dconstvisitor.h | 2 + src/libs/modelinglib/qmt/diagram/dvisitor.h | 2 + .../qmt/diagram_controller/dclonevisitor.cpp | 15 + .../qmt/diagram_controller/dclonevisitor.h | 2 + .../qmt/diagram_controller/dfactory.cpp | 9 + .../qmt/diagram_controller/dfactory.h | 1 + .../dflatassignmentvisitor.cpp | 12 + .../dflatassignmentvisitor.h | 1 + .../qmt/diagram_controller/dupdatevisitor.cpp | 22 ++ .../qmt/diagram_controller/dupdatevisitor.h | 1 + .../qmt/diagram_controller/dvoidvisitor.cpp | 11 + .../qmt/diagram_controller/dvoidvisitor.h | 2 + .../diagramscenemodelitemvisitors.cpp | 13 + .../diagramscenemodelitemvisitors.h | 2 + .../diagram_scene/items/connectionitem.cpp | 170 +++++++++++ .../qmt/diagram_scene/items/connectionitem.h | 64 ++++ .../qmt/diagram_scene/items/objectitem.cpp | 2 + .../qmt/diagram_scene/items/relationitem.cpp | 43 +++ .../diagram_scene/parts/relationstarter.cpp | 3 +- .../modelinglib/qmt/model/mconnection.cpp | 114 +++++++ src/libs/modelinglib/qmt/model/mconnection.h | 85 ++++++ .../modelinglib/qmt/model/mconstvisitor.h | 2 + src/libs/modelinglib/qmt/model/mvisitor.h | 2 + .../qmt/model_controller/mchildrenvisitor.cpp | 6 + .../qmt/model_controller/mchildrenvisitor.h | 1 + .../qmt/model_controller/mclonevisitor.cpp | 15 + .../qmt/model_controller/mclonevisitor.h | 2 + .../mflatassignmentvisitor.cpp | 12 + .../model_controller/mflatassignmentvisitor.h | 1 + .../qmt/model_controller/mvoidvisitor.cpp | 11 + .../qmt/model_controller/mvoidvisitor.h | 2 + .../modelinglib/qmt/model_ui/treemodel.cpp | 15 + .../model_widgets_ui/propertiesviewmview.cpp | 288 ++++++++++++++---- .../model_widgets_ui/propertiesviewmview.h | 11 + src/libs/modelinglib/qmt/qmt.pri | 6 + .../qmt/serializer/diagramserializer.cpp | 34 +++ .../qmt/serializer/modelserializer.cpp | 34 +++ .../qmt/tasks/alignonrastervisitor.cpp | 6 + .../qmt/tasks/alignonrastervisitor.h | 1 + .../qmt/tasks/diagramscenecontroller.cpp | 42 +++ .../qmt/tasks/diagramscenecontroller.h | 5 + .../modeleditor/openelementvisitor.cpp | 11 + src/plugins/modeleditor/openelementvisitor.h | 2 + 47 files changed, 1252 insertions(+), 73 deletions(-) create mode 100644 src/libs/modelinglib/qmt/diagram/dconnection.cpp create mode 100644 src/libs/modelinglib/qmt/diagram/dconnection.h create mode 100644 src/libs/modelinglib/qmt/diagram_scene/items/connectionitem.cpp create mode 100644 src/libs/modelinglib/qmt/diagram_scene/items/connectionitem.h create mode 100644 src/libs/modelinglib/qmt/model/mconnection.cpp create mode 100644 src/libs/modelinglib/qmt/model/mconnection.h diff --git a/share/qtcreator/modeleditor/standard.def b/share/qtcreator/modeleditor/standard.def index aa4afd04e2..319473340e 100644 --- a/share/qtcreator/modeleditor/standard.def +++ b/share/qtcreator/modeleditor/standard.def @@ -64,13 +64,13 @@ // role: // cardinality: // navigable: -// Shape { -// } +// head: // } // } // // -// A Dependency defines a number of settings of a dependency specialization: +// A Dependency defines settings of a dependency specialization: // // Dependency { // id: @@ -183,24 +183,24 @@ Icon { } Association { - id: AggregationOne - title: "Aggregation (?:1)" + id: Aggregation + title: "Aggregation" End { end: A - cardinality: 1 + cardinality: "*" navigable: yes relationship: aggregation } } Association { - id: AggregationMany - title: "Aggregation (?:N)" + id: Composition + title: "Composition" End { end: A - cardinality: "*" + cardinality: "1" navigable: yes - relationship: aggregation + relationship: composition } } @@ -215,8 +215,8 @@ Toolbar { Tool { element: dependency } Tool { element: inheritance } Tool { element: association } - Tool { element: AggregationOne } - Tool { element: AggregationMany } + Tool { element: Aggregation } + Tool { element: Composition } } } @@ -304,6 +304,29 @@ Icon { } } +Relation { + id: Communication + elements: UseCase, Actor + pattern: solid + color: A + End { + end: A + } + End { + end: B + } +} + +Toolbar { + id: UseCaseToolbar + element: UseCase, Actor + Tools { + Tool { element: Communication } + Tool { element: dependency } + } +} + + // **************** // ** Activities ** // **************** @@ -409,15 +432,11 @@ Relation { End { end: A elements: Start, Activity, Condition, HorizontalBar, VerticalBar - role: "" } End { end: B elements: Activity, Condition, HorizontalBar, VerticalBar, Termination - head: filledtriangle - //Shape { - // Triangle { x: 6; y: 5.2; width: 12; height: 10.4; filled: yes } - //} + head: arrow } } diff --git a/src/libs/modelinglib/modelinglib.qbs b/src/libs/modelinglib/modelinglib.qbs index e4b26be806..305bf6afdc 100644 --- a/src/libs/modelinglib/modelinglib.qbs +++ b/src/libs/modelinglib/modelinglib.qbs @@ -55,6 +55,8 @@ QtcLibrary { "diagram/dclass.h", "diagram/dcomponent.cpp", "diagram/dcomponent.h", + "diagram/dconnection.cpp", + "diagram/dconnection.h", "diagram/dconstvisitor.h", "diagram/ddependency.cpp", "diagram/ddependency.h", @@ -114,6 +116,8 @@ QtcLibrary { "diagram_scene/items/classitem.h", "diagram_scene/items/componentitem.cpp", "diagram_scene/items/componentitem.h", + "diagram_scene/items/connectionitem.cpp", + "diagram_scene/items/connectionitem.h", "diagram_scene/items/diagramitem.cpp", "diagram_scene/items/diagramitem.h", "diagram_scene/items/itemitem.cpp", @@ -188,6 +192,8 @@ QtcLibrary { "model/mclassmember.h", "model/mcomponent.cpp", "model/mcomponent.h", + "model/mconnection.cpp", + "model/mconnection.h", "model/mconstvisitor.h", "model/mdependency.cpp", "model/mdependency.h", diff --git a/src/libs/modelinglib/qmt/diagram/dconnection.cpp b/src/libs/modelinglib/qmt/diagram/dconnection.cpp new file mode 100644 index 0000000000..a5611795fc --- /dev/null +++ b/src/libs/modelinglib/qmt/diagram/dconnection.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jochen Becher +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "dconnection.h" + +#include "dvisitor.h" +#include "dconstvisitor.h" + +namespace qmt { + +DConnectionEnd::DConnectionEnd() +{ +} + +DConnectionEnd::~DConnectionEnd() +{ +} + +void DConnectionEnd::setName(const QString &name) +{ + m_name = name; +} + +void DConnectionEnd::setCardinatlity(const QString &cardinality) +{ + m_cardinality = cardinality; +} + +void DConnectionEnd::setNavigable(bool navigable) +{ + m_isNavigable = navigable; +} + +bool operator==(const DConnectionEnd &lhs, const DConnectionEnd &rhs) +{ + if (&lhs == &rhs) + return true; + return lhs.name() == rhs.name() + && lhs.cardinality() == rhs.cardinality() + && lhs.isNavigable() == rhs.isNavigable(); +} + +bool operator!=(const DConnectionEnd &lhs, const DConnectionEnd &rhs) +{ + return !operator==(lhs, rhs); +} + +DConnection::DConnection() +{ +} + +DConnection::~DConnection() +{ +} + +void DConnection::setCustomRelationId(const QString &customRelationId) +{ + m_customRelationId = customRelationId; +} + +void DConnection::setEndA(const DConnectionEnd &endA) +{ + m_endA = endA; +} + +void DConnection::setEndB(const DConnectionEnd &endB) +{ + m_endB = endB; +} + +void DConnection::accept(DVisitor *visitor) +{ + visitor->visitDConnection(this); +} + +void DConnection::accept(DConstVisitor *visitor) const +{ + visitor->visitDConnection(this); +} + +} // namespace qmt diff --git a/src/libs/modelinglib/qmt/diagram/dconnection.h b/src/libs/modelinglib/qmt/diagram/dconnection.h new file mode 100644 index 0000000000..4100142eef --- /dev/null +++ b/src/libs/modelinglib/qmt/diagram/dconnection.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jochen Becher +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "drelation.h" + +#include "qmt/model/mconnection.h" + +namespace qmt { + +class QMT_EXPORT DConnectionEnd +{ +public: + DConnectionEnd(); + ~DConnectionEnd(); + + QString name() const { return m_name; } + void setName(const QString &name); + QString cardinality() const { return m_cardinality; } + void setCardinatlity(const QString &cardinality); + bool isNavigable() const { return m_isNavigable; } + void setNavigable(bool navigable); + +private: + QString m_name; + QString m_cardinality; + bool m_isNavigable = false; +}; + +bool operator==(const DConnectionEnd &lhs, const DConnectionEnd &rhs); +bool operator!=(const DConnectionEnd &lhs, const DConnectionEnd &rhs); + +class QMT_EXPORT DConnection : public DRelation +{ +public: + DConnection(); + ~DConnection() override; + + QString customRelationId() const { return m_customRelationId; } + void setCustomRelationId(const QString &customRelationId); + DConnectionEnd endA() const { return m_endA; } + void setEndA(const DConnectionEnd &endA); + DConnectionEnd endB() const { return m_endB; } + void setEndB(const DConnectionEnd &endB); + + void accept(DVisitor *visitor) override; + void accept(DConstVisitor *visitor) const override; + +private: + QString m_customRelationId; + DConnectionEnd m_endA; + DConnectionEnd m_endB; +}; + +} // namespace qmt diff --git a/src/libs/modelinglib/qmt/diagram/dconstvisitor.h b/src/libs/modelinglib/qmt/diagram/dconstvisitor.h index 23bdb91d58..4637bd767c 100644 --- a/src/libs/modelinglib/qmt/diagram/dconstvisitor.h +++ b/src/libs/modelinglib/qmt/diagram/dconstvisitor.h @@ -38,6 +38,7 @@ class DRelation; class DInheritance; class DDependency; class DAssociation; +class DConnection; class DAnnotation; class DBoundary; @@ -57,6 +58,7 @@ public: virtual void visitDInheritance(const DInheritance *inheritance) = 0; virtual void visitDDependency(const DDependency *dependency) = 0; virtual void visitDAssociation(const DAssociation *association) = 0; + virtual void visitDConnection(const DConnection *connection) = 0; virtual void visitDAnnotation(const DAnnotation *annotation) = 0; virtual void visitDBoundary(const DBoundary *boundary) = 0; }; diff --git a/src/libs/modelinglib/qmt/diagram/dvisitor.h b/src/libs/modelinglib/qmt/diagram/dvisitor.h index bb9e7873ee..919aa53233 100644 --- a/src/libs/modelinglib/qmt/diagram/dvisitor.h +++ b/src/libs/modelinglib/qmt/diagram/dvisitor.h @@ -38,6 +38,7 @@ class DRelation; class DInheritance; class DDependency; class DAssociation; +class DConnection; class DAnnotation; class DBoundary; @@ -57,6 +58,7 @@ public: virtual void visitDInheritance(DInheritance *inheritance) = 0; virtual void visitDDependency(DDependency *dependency) = 0; virtual void visitDAssociation(DAssociation *association) = 0; + virtual void visitDConnection(DConnection *connection) = 0; virtual void visitDAnnotation(DAnnotation *annotation) = 0; virtual void visitDBoundary(DBoundary *boundary) = 0; }; diff --git a/src/libs/modelinglib/qmt/diagram_controller/dclonevisitor.cpp b/src/libs/modelinglib/qmt/diagram_controller/dclonevisitor.cpp index c9e2067c8b..c440d80378 100644 --- a/src/libs/modelinglib/qmt/diagram_controller/dclonevisitor.cpp +++ b/src/libs/modelinglib/qmt/diagram_controller/dclonevisitor.cpp @@ -36,6 +36,7 @@ #include "qmt/diagram/dinheritance.h" #include "qmt/diagram/ddependency.h" #include "qmt/diagram/dassociation.h" +#include "qmt/diagram/dconnection.h" #include "qmt/diagram/dannotation.h" #include "qmt/diagram/dboundary.h" #include "qmt/infrastructure/qmtassert.h" @@ -122,6 +123,13 @@ void DCloneVisitor::visitDAssociation(const DAssociation *association) visitDRelation(association); } +void DCloneVisitor::visitDConnection(const DConnection *connection) +{ + if (!m_cloned) + m_cloned = new DConnection(*connection); + visitDRelation(connection); +} + void DCloneVisitor::visitDAnnotation(const DAnnotation *annotation) { if (!m_cloned) @@ -215,6 +223,13 @@ void DCloneDeepVisitor::visitDAssociation(const DAssociation *association) visitDRelation(association); } +void DCloneDeepVisitor::visitDConnection(const DConnection *connection) +{ + if (!m_cloned) + m_cloned = new DConnection(*connection); + visitDRelation(connection); +} + void DCloneDeepVisitor::visitDAnnotation(const DAnnotation *annotation) { if (!m_cloned) diff --git a/src/libs/modelinglib/qmt/diagram_controller/dclonevisitor.h b/src/libs/modelinglib/qmt/diagram_controller/dclonevisitor.h index c69534b542..b373f632f1 100644 --- a/src/libs/modelinglib/qmt/diagram_controller/dclonevisitor.h +++ b/src/libs/modelinglib/qmt/diagram_controller/dclonevisitor.h @@ -48,6 +48,7 @@ public: void visitDInheritance(const DInheritance *inheritance) override; void visitDDependency(const DDependency *dependency) override; void visitDAssociation(const DAssociation *association) override; + void visitDConnection(const DConnection *connection) override; void visitDAnnotation(const DAnnotation *annotation) override; void visitDBoundary(const DBoundary *boundary) override; @@ -73,6 +74,7 @@ public: void visitDInheritance(const DInheritance *inheritance) override; void visitDDependency(const DDependency *dependency) override; void visitDAssociation(const DAssociation *association) override; + void visitDConnection(const DConnection *connection) override; void visitDAnnotation(const DAnnotation *annotation) override; void visitDBoundary(const DBoundary *boundary) override; diff --git a/src/libs/modelinglib/qmt/diagram_controller/dfactory.cpp b/src/libs/modelinglib/qmt/diagram_controller/dfactory.cpp index dcbe5845ca..c4c9c4fc31 100644 --- a/src/libs/modelinglib/qmt/diagram_controller/dfactory.cpp +++ b/src/libs/modelinglib/qmt/diagram_controller/dfactory.cpp @@ -36,6 +36,7 @@ #include "qmt/diagram/dinheritance.h" #include "qmt/diagram/ddependency.h" #include "qmt/diagram/dassociation.h" +#include "qmt/diagram/dconnection.h" #include "qmt/model/melement.h" #include "qmt/model/mobject.h" @@ -149,4 +150,12 @@ void DFactory::visitMAssociation(const MAssociation *association) visitMRelation(association); } +void DFactory::visitMConnection(const MConnection *connection) +{ + QMT_CHECK(!m_product); + auto diagramConnection = new DConnection(); + m_product = diagramConnection; + visitMRelation(connection); +} + } // namespace qmt diff --git a/src/libs/modelinglib/qmt/diagram_controller/dfactory.h b/src/libs/modelinglib/qmt/diagram_controller/dfactory.h index 5d5e48ded8..d2933ff15f 100644 --- a/src/libs/modelinglib/qmt/diagram_controller/dfactory.h +++ b/src/libs/modelinglib/qmt/diagram_controller/dfactory.h @@ -51,6 +51,7 @@ public: void visitMDependency(const MDependency *dependency) override; void visitMInheritance(const MInheritance *inheritance) override; void visitMAssociation(const MAssociation *association) override; + void visitMConnection(const MConnection *connection) override; private: DElement *m_product; diff --git a/src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.cpp b/src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.cpp index 332c9c0c14..e3242fff91 100644 --- a/src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.cpp +++ b/src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.cpp @@ -36,6 +36,7 @@ #include "qmt/diagram/dinheritance.h" #include "qmt/diagram/ddependency.h" #include "qmt/diagram/dassociation.h" +#include "qmt/diagram/dconnection.h" #include "qmt/diagram/dannotation.h" #include "qmt/diagram/dboundary.h" #include "qmt/infrastructure/qmtassert.h" @@ -142,6 +143,17 @@ void DFlatAssignmentVisitor::visitDAssociation(const DAssociation *association) QMT_ASSERT(target, return); target->setEndA(association->endA()); target->setEndB(association->endB()); + // TODO assign assoziation class? +} + +void DFlatAssignmentVisitor::visitDConnection(const DConnection *connection) +{ + visitDRelation(connection); + auto target = dynamic_cast(m_target); + QMT_CHECK(target); + target->setCustomRelationId(connection->customRelationId()); + target->setEndA(connection->endA()); + target->setEndB(connection->endB()); } void DFlatAssignmentVisitor::visitDAnnotation(const DAnnotation *annotation) diff --git a/src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.h b/src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.h index 8c2537ab05..7aedfc5d8b 100644 --- a/src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.h +++ b/src/libs/modelinglib/qmt/diagram_controller/dflatassignmentvisitor.h @@ -46,6 +46,7 @@ public: void visitDInheritance(const DInheritance *inheritance) override; void visitDDependency(const DDependency *dependency) override; void visitDAssociation(const DAssociation *association) override; + void visitDConnection(const DConnection *connection) override; void visitDAnnotation(const DAnnotation *annotation) override; void visitDBoundary(const DBoundary *boundary) override; diff --git a/src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.cpp b/src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.cpp index ade79dfa90..4dfbc6eeb2 100644 --- a/src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.cpp +++ b/src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.cpp @@ -32,6 +32,7 @@ #include "qmt/diagram/drelation.h" #include "qmt/diagram/ddependency.h" #include "qmt/diagram/dassociation.h" +#include "qmt/diagram/dconnection.h" #include "qmt/model/melement.h" #include "qmt/model/mobject.h" @@ -222,6 +223,27 @@ void DUpdateVisitor::visitMAssociation(const MAssociation *association) visitMRelation(association); } +void DUpdateVisitor::visitMConnection(const MConnection *connection) +{ + auto dconnection = dynamic_cast(m_target); + QMT_CHECK(dconnection); + if (isUpdating(connection->customRelationId() != dconnection->customRelationId())) + dconnection->setCustomRelationId(connection->customRelationId()); + DConnectionEnd endA; + endA.setName(connection->endA().name()); + endA.setCardinatlity(connection->endA().cardinality()); + endA.setNavigable(connection->endA().isNavigable()); + if (isUpdating(endA != dconnection->endA())) + dconnection->setEndA(endA); + DConnectionEnd endB; + endB.setName(connection->endB().name()); + endB.setCardinatlity(connection->endB().cardinality()); + endB.setNavigable(connection->endB().isNavigable()); + if (isUpdating(endB != dconnection->endB())) + dconnection->setEndB(endB); + visitMRelation(connection); +} + bool DUpdateVisitor::isUpdating(bool valueChanged) { if (m_checkNeedsUpdate) { diff --git a/src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.h b/src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.h index e88e9eed4b..865040945d 100644 --- a/src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.h +++ b/src/libs/modelinglib/qmt/diagram_controller/dupdatevisitor.h @@ -52,6 +52,7 @@ public: void visitMDependency(const MDependency *dependency) override; void visitMInheritance(const MInheritance *inheritance) override; void visitMAssociation(const MAssociation *association) override; + void visitMConnection(const MConnection *connection) override; private: bool isUpdating(bool valueChanged); diff --git a/src/libs/modelinglib/qmt/diagram_controller/dvoidvisitor.cpp b/src/libs/modelinglib/qmt/diagram_controller/dvoidvisitor.cpp index 09b7c92d50..a51f0e0335 100644 --- a/src/libs/modelinglib/qmt/diagram_controller/dvoidvisitor.cpp +++ b/src/libs/modelinglib/qmt/diagram_controller/dvoidvisitor.cpp @@ -36,6 +36,7 @@ #include "qmt/diagram/dinheritance.h" #include "qmt/diagram/ddependency.h" #include "qmt/diagram/dassociation.h" +#include "qmt/diagram/dconnection.h" #include "qmt/diagram/dannotation.h" #include "qmt/diagram/dboundary.h" @@ -100,6 +101,11 @@ void DVoidVisitor::visitDAssociation(DAssociation *association) visitDRelation(association); } +void DVoidVisitor::visitDConnection(DConnection *connection) +{ + visitDRelation(connection); +} + void DVoidVisitor::visitDAnnotation(DAnnotation *annotation) { visitDElement(annotation); @@ -169,6 +175,11 @@ void DConstVoidVisitor::visitDAssociation(const DAssociation *association) visitDRelation(association); } +void DConstVoidVisitor::visitDConnection(const DConnection *connection) +{ + visitDRelation(connection); +} + void DConstVoidVisitor::visitDAnnotation(const DAnnotation *annotation) { visitDElement(annotation); diff --git a/src/libs/modelinglib/qmt/diagram_controller/dvoidvisitor.h b/src/libs/modelinglib/qmt/diagram_controller/dvoidvisitor.h index 4519c1a943..f1f1a23f56 100644 --- a/src/libs/modelinglib/qmt/diagram_controller/dvoidvisitor.h +++ b/src/libs/modelinglib/qmt/diagram_controller/dvoidvisitor.h @@ -47,6 +47,7 @@ public: void visitDInheritance(DInheritance *inheritance) override; void visitDDependency(DDependency *dependency) override; void visitDAssociation(DAssociation *association) override; + void visitDConnection(DConnection *connection) override; void visitDAnnotation(DAnnotation *annotation) override; void visitDBoundary(DBoundary *boundary) override; }; @@ -67,6 +68,7 @@ public: void visitDInheritance(const DInheritance *inheritance) override; void visitDDependency(const DDependency *dependency) override; void visitDAssociation(const DAssociation *association) override; + void visitDConnection(const DConnection *connection) override; void visitDAnnotation(const DAnnotation *annotation) override; void visitDBoundary(const DBoundary *boundary) override; }; diff --git a/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodelitemvisitors.cpp b/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodelitemvisitors.cpp index 2b5ca59228..540d887941 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodelitemvisitors.cpp +++ b/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodelitemvisitors.cpp @@ -32,6 +32,7 @@ #include "items/itemitem.h" #include "items/relationitem.h" #include "items/associationitem.h" +#include "items/connectionitem.h" #include "items/annotationitem.h" #include "items/boundaryitem.h" @@ -46,6 +47,7 @@ #include "qmt/diagram/dinheritance.h" #include "qmt/diagram/ddependency.h" #include "qmt/diagram/dassociation.h" +#include "qmt/diagram/dconnection.h" #include "qmt/diagram/dannotation.h" #include "qmt/diagram/dboundary.h" #include "qmt/infrastructure/qmtassert.h" @@ -122,6 +124,12 @@ void DiagramSceneModel::CreationVisitor::visitDAssociation(DAssociation *associa m_graphicsItem = new AssociationItem(association, m_diagramSceneModel); } +void DiagramSceneModel::CreationVisitor::visitDConnection(DConnection *connection) +{ + QMT_CHECK(!m_graphicsItem); + m_graphicsItem = new ConnectionItem(connection, m_diagramSceneModel); +} + void DiagramSceneModel::CreationVisitor::visitDAnnotation(DAnnotation *annotation) { QMT_CHECK(!m_graphicsItem); @@ -262,6 +270,11 @@ void DiagramSceneModel::UpdateVisitor::visitDAssociation(DAssociation *associati visitDRelation(association); } +void DiagramSceneModel::UpdateVisitor::visitDConnection(DConnection *connection) +{ + visitDRelation(connection); +} + void DiagramSceneModel::UpdateVisitor::visitDAnnotation(DAnnotation *annotation) { Q_UNUSED(annotation); // avoid warning in release mode diff --git a/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodelitemvisitors.h b/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodelitemvisitors.h index 138f087481..193f30223b 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodelitemvisitors.h +++ b/src/libs/modelinglib/qmt/diagram_scene/diagramscenemodelitemvisitors.h @@ -49,6 +49,7 @@ public: void visitDInheritance(DInheritance *inheritance) override; void visitDDependency(DDependency *dependency) override; void visitDAssociation(DAssociation *association) override; + void visitDConnection(DConnection *connection) override; void visitDAnnotation(DAnnotation *annotation) override; void visitDBoundary(DBoundary *boundary) override; @@ -74,6 +75,7 @@ public: void visitDInheritance(DInheritance *inheritance) override; void visitDDependency(DDependency *dependency) override; void visitDAssociation(DAssociation *association) override; + void visitDConnection(DConnection *connection) override; void visitDAnnotation(DAnnotation *annotation) override; void visitDBoundary(DBoundary *boundary) override; diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/connectionitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/connectionitem.cpp new file mode 100644 index 0000000000..c0d2833537 --- /dev/null +++ b/src/libs/modelinglib/qmt/diagram_scene/items/connectionitem.cpp @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jochen Becher +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "connectionitem.h" + +#include "qmt/diagram_controller/diagramcontroller.h" +#include "qmt/diagram/dconnection.h" +#include "qmt/diagram_scene/capabilities/intersectionable.h" +#include "qmt/diagram_scene/diagramscenemodel.h" +#include "qmt/diagram_scene/parts/arrowitem.h" +#include "qmt/infrastructure/geometryutilities.h" +#include "qmt/infrastructure/qmtassert.h" +#include "qmt/style/style.h" + +#include +#include +#include +#include +#include +#include + +namespace qmt { + +ConnectionItem::ConnectionItem(DConnection *connection, DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent) + : RelationItem(connection, diagramSceneModel, parent), + m_connection(connection) +{ +} + +ConnectionItem::~ConnectionItem() +{ +} + +void ConnectionItem::update(const Style *style) +{ + RelationItem::update(style); + + updateEndLabels(m_connection->endA(), m_connection->endB(), &m_endAName, &m_endACardinality, style); + updateEndLabels(m_connection->endB(), m_connection->endA(), &m_endBName, &m_endBCardinality, style); + + QMT_CHECK(m_arrow); + QGraphicsItem *endAItem = m_diagramSceneModel->graphicsItem(m_connection->endAUid()); + if (!endAItem) + return; + placeEndLabels(m_arrow->firstLineSegment(), m_endAName, m_endACardinality, endAItem, m_arrow->startHeadLength()); + QGraphicsItem *endBItem = m_diagramSceneModel->graphicsItem(m_connection->endBUid()); + if (!endBItem) + return; + placeEndLabels(m_arrow->lastLineSegment(), m_endBName, m_endBCardinality, endBItem, m_arrow->endHeadLength()); +} + +void ConnectionItem::updateEndLabels(const DConnectionEnd &end, const DConnectionEnd &otherEnd, + QGraphicsSimpleTextItem **endName, QGraphicsSimpleTextItem **endCardinality, + const Style *style) +{ + Q_UNUSED(end); + + if (!otherEnd.name().isEmpty()) { + if (!*endName) + *endName = new QGraphicsSimpleTextItem(this); + (*endName)->setFont(style->smallFont()); + (*endName)->setBrush(style->textBrush()); + (*endName)->setText(otherEnd.name()); + } else if (*endName) { + (*endName)->scene()->removeItem(*endName); + delete *endName; + *endName = 0; + } + + if (!otherEnd.cardinality().isEmpty()) { + if (!*endCardinality) + *endCardinality = new QGraphicsSimpleTextItem(this); + (*endCardinality)->setFont(style->smallFont()); + (*endCardinality)->setBrush(style->textBrush()); + (*endCardinality)->setText(otherEnd.cardinality()); + } else if (*endCardinality) { + (*endCardinality)->scene()->removeItem(*endCardinality); + delete *endCardinality; + *endCardinality = 0; + } +} + +void ConnectionItem::placeEndLabels(const QLineF &lineSegment, QGraphicsItem *endName, QGraphicsItem *endCardinality, + QGraphicsItem *endItem, double headLength) +{ + const double HEAD_OFFSET = headLength + 6.0; + const double SIDE_OFFSET = 4.0; + QPointF headOffset = QPointF(HEAD_OFFSET, 0); + QPointF sideOffset = QPointF(0.0, SIDE_OFFSET); + + double angle = GeometryUtilities::calcAngle(lineSegment); + if (angle >= -5 && angle <= 5) { + if (endName) + endName->setPos(lineSegment.p1() + headOffset + sideOffset); + if (endCardinality) + endCardinality->setPos(lineSegment.p1() + headOffset - sideOffset + - endCardinality->boundingRect().bottomLeft()); + } else if (angle <= -175 || angle >= 175) { + if (endName) + endName->setPos(lineSegment.p1() - headOffset + sideOffset - endName->boundingRect().topRight()); + if (endCardinality) + endCardinality->setPos(lineSegment.p1() - headOffset + - sideOffset - endCardinality->boundingRect().bottomRight()); + } else { + QRectF rect; + if (endCardinality) + rect = endCardinality->boundingRect(); + if (endName) + rect = rect.united(endName->boundingRect().translated(rect.bottomLeft())); + + QPointF rectPlacement; + GeometryUtilities::Side alignedSide = GeometryUtilities::SideUnspecified; + + if (auto objectItem = dynamic_cast(endItem)) { + QPointF intersectionPoint; + QLineF intersectionLine; + + if (objectItem->intersectShapeWithLine(GeometryUtilities::stretch(lineSegment.translated(pos()), 2.0, 0.0), + &intersectionPoint, &intersectionLine)) { + if (!GeometryUtilities::placeRectAtLine(rect, lineSegment, HEAD_OFFSET, SIDE_OFFSET, + intersectionLine, &rectPlacement, &alignedSide)) { + rectPlacement = intersectionPoint; + } + } else { + rectPlacement = lineSegment.p1(); + } + } else { + rectPlacement = endItem->pos(); + } + + if (endCardinality) { + if (alignedSide == GeometryUtilities::SideRight) + endCardinality->setPos(rectPlacement + + QPointF(rect.width() - endCardinality->boundingRect().width(), 0.0)); + else + endCardinality->setPos(rectPlacement); + rectPlacement += endCardinality->boundingRect().bottomLeft(); + } + if (endName) { + if (alignedSide == GeometryUtilities::SideRight) + endName->setPos(rectPlacement + QPointF(rect.width() - endName->boundingRect().width(), 0.0)); + else + endName->setPos(rectPlacement); + } + } +} + +} // namespace qmt diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/connectionitem.h b/src/libs/modelinglib/qmt/diagram_scene/items/connectionitem.h new file mode 100644 index 0000000000..cc4e747bbb --- /dev/null +++ b/src/libs/modelinglib/qmt/diagram_scene/items/connectionitem.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jochen Becher +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "relationitem.h" + +QT_BEGIN_NAMESPACE +class QGraphicsSimpleTextItem; +QT_END_NAMESPACE + +namespace qmt { + +class DConnection; +class DConnectionEnd; + +class ConnectionItem : public RelationItem +{ +public: + ConnectionItem(DConnection *connection, DiagramSceneModel *diagramSceneModel, + QGraphicsItem *parent = 0); + ~ConnectionItem() override; + +protected: + void update(const Style *style) override; + +private: + void updateEndLabels(const DConnectionEnd &end, const DConnectionEnd &otherEnd, + QGraphicsSimpleTextItem **endName, + QGraphicsSimpleTextItem **endCardinality, const Style *style); + void placeEndLabels(const QLineF &lineSegment, QGraphicsItem *endName, + QGraphicsItem *endCardinality, + QGraphicsItem *endItem, double headLength); + + DConnection *m_connection = 0; + QGraphicsSimpleTextItem *m_endAName = 0; + QGraphicsSimpleTextItem *m_endACardinality = 0; + QGraphicsSimpleTextItem *m_endBName = 0; + QGraphicsSimpleTextItem *m_endBCardinality = 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 d244f5366d..f3baab3392 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp +++ b/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp @@ -360,6 +360,8 @@ void ObjectItem::relationDrawn(const QString &id, ObjectItem *targetItem, const return; } // create relation + diagramSceneController->createConnection(id, object(), relatedObject, intermediatePoints, + diagramSceneModel()->diagram()); } break; } diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.cpp index a2779066bc..3a3428b4e7 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.cpp +++ b/src/libs/modelinglib/qmt/diagram_scene/items/relationitem.cpp @@ -28,6 +28,7 @@ #include "qmt/diagram_controller/diagramcontroller.h" #include "qmt/diagram_controller/dvoidvisitor.h" #include "qmt/diagram/dassociation.h" +#include "qmt/diagram/dconnection.h" #include "qmt/diagram/ddependency.h" #include "qmt/diagram/dinheritance.h" #include "qmt/diagram/dobject.h" @@ -41,6 +42,8 @@ #include "qmt/diagram_scene/parts/stereotypesitem.h" #include "qmt/infrastructure/geometryutilities.h" #include "qmt/infrastructure/qmtassert.h" +#include "qmt/stereotype/customrelation.h" +#include "qmt/stereotype/stereotypecontroller.h" #include "qmt/style/stylecontroller.h" #include "qmt/style/styledrelation.h" #include "qmt/style/style.h" @@ -166,6 +169,46 @@ public: m_arrow->setPoints(m_points); } + void visitDConnection(const DConnection *connection) + { + + ArrowItem::Shaft shaft = ArrowItem::ShaftSolid; + ArrowItem::Head endAHead = ArrowItem::HeadNone; + ArrowItem::Head endBHead = ArrowItem::HeadNone; + + CustomRelation customRelation = m_diagramSceneModel->stereotypeController()->findCustomRelation(connection->customRelationId()); + if (!customRelation.isNull()) { + // 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()); + endAHead = head2head.value(customRelation.endA().head()); + endBHead = head2head.value(customRelation.endB().head()); + // TODO color + } + + m_arrow->setShaft(shaft); + m_arrow->setArrowSize(12.0); + m_arrow->setDiamondSize(12.0); + m_arrow->setStartHead(endAHead); + m_arrow->setEndHead(endBHead); + m_arrow->setPoints(m_points); + } + private: DiagramSceneModel *m_diagramSceneModel = 0; ArrowItem *m_arrow = 0; diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.cpp b/src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.cpp index c795394d6d..8983b5fbb8 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.cpp +++ b/src/libs/modelinglib/qmt/diagram_scene/parts/relationstarter.cpp @@ -81,8 +81,7 @@ void RelationStarter::addArrow(const QString &id, ArrowItem::Shaft shaft, arrow->setShaft(shaft); arrow->setStartHead(startHead); arrow->setEndHead(endHead); - if (!toolTip.isEmpty()) - arrow->setToolTip(toolTip); + arrow->setToolTip(toolTip.isEmpty() ? id : 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()); diff --git a/src/libs/modelinglib/qmt/model/mconnection.cpp b/src/libs/modelinglib/qmt/model/mconnection.cpp new file mode 100644 index 0000000000..2d8ab6c2c3 --- /dev/null +++ b/src/libs/modelinglib/qmt/model/mconnection.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jochen Becher +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "mconnection.h" + +#include "mvisitor.h" +#include "mconstvisitor.h" + +namespace qmt { + +MConnectionEnd::MConnectionEnd() +{ +} + +MConnectionEnd::MConnectionEnd(const MConnectionEnd &rhs) + : m_name(rhs.name()), + m_cardinality(rhs.m_cardinality), + m_isNavigable(rhs.m_isNavigable) +{ +} + +MConnectionEnd::~MConnectionEnd() +{ +} + +MConnectionEnd &MConnectionEnd::operator=(const MConnectionEnd &rhs) +{ + if (this != &rhs) { + m_name = rhs.m_name; + m_cardinality = rhs.m_cardinality; + m_isNavigable = rhs.m_isNavigable; + } + return *this; +} + +void MConnectionEnd::setName(const QString &name) +{ + m_name = name; +} + +void MConnectionEnd::setCardinality(const QString &cardinality) +{ + m_cardinality = cardinality; +} + +void MConnectionEnd::setNavigable(bool navigable) +{ + m_isNavigable = navigable; +} + +bool operator==(const MConnectionEnd &lhs, const MConnectionEnd &rhs) +{ + return lhs.name() == rhs.name() + && lhs.cardinality() == rhs.cardinality() + && lhs.isNavigable() == rhs.isNavigable(); +} + +MConnection::MConnection() + : MRelation() +{ +} + +MConnection::~MConnection() +{ +} + +void MConnection::setCustomRelationId(const QString &customRelationId) +{ + m_customRelationId = customRelationId; +} + +void MConnection::setEndA(const MConnectionEnd &end) +{ + m_endA = end; +} + +void MConnection::setEndB(const MConnectionEnd &end) +{ + m_endB = end; +} + +void MConnection::accept(MVisitor *visitor) +{ + visitor->visitMConnection(this); +} + +void MConnection::accept(MConstVisitor *visitor) const +{ + visitor->visitMConnection(this); +} + +} // namespace qmt diff --git a/src/libs/modelinglib/qmt/model/mconnection.h b/src/libs/modelinglib/qmt/model/mconnection.h new file mode 100644 index 0000000000..2fe10fcbc5 --- /dev/null +++ b/src/libs/modelinglib/qmt/model/mconnection.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jochen Becher +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "mrelation.h" +#include "qmt/infrastructure/handle.h" + +#include + +namespace qmt { + +class QMT_EXPORT MConnectionEnd +{ +public: + MConnectionEnd(); + MConnectionEnd(const MConnectionEnd &rhs); + ~MConnectionEnd(); + + MConnectionEnd &operator=(const MConnectionEnd &rhs); + + QString name() const { return m_name; } + void setName(const QString &name); + QString cardinality() const { return m_cardinality; } + void setCardinality(const QString &cardinality); + bool isNavigable() const { return m_isNavigable; } + void setNavigable(bool navigable); + +private: + QString m_name; + QString m_cardinality; + bool m_isNavigable = false; +}; + +bool operator==(const MConnectionEnd &lhs, const MConnectionEnd &rhs); +inline bool operator!=(const MConnectionEnd &lhs, const MConnectionEnd &rhs) +{ + return !(lhs == rhs); +} + +class QMT_EXPORT MConnection : public MRelation +{ +public: + MConnection(); + ~MConnection() override; + + QString customRelationId() const { return m_customRelationId; } + void setCustomRelationId(const QString &customRelationId); + MConnectionEnd endA() const { return m_endA; } + void setEndA(const MConnectionEnd &end); + MConnectionEnd endB() const { return m_endB; } + void setEndB(const MConnectionEnd &end); + + void accept(MVisitor *visitor) override; + void accept(MConstVisitor *visitor) const override; + +private: + QString m_customRelationId; + MConnectionEnd m_endA; + MConnectionEnd m_endB; +}; + +} // namespace qmt diff --git a/src/libs/modelinglib/qmt/model/mconstvisitor.h b/src/libs/modelinglib/qmt/model/mconstvisitor.h index fcfa9665fc..5ef7182726 100644 --- a/src/libs/modelinglib/qmt/model/mconstvisitor.h +++ b/src/libs/modelinglib/qmt/model/mconstvisitor.h @@ -41,6 +41,7 @@ class MRelation; class MDependency; class MInheritance; class MAssociation; +class MConnection; class MConstVisitor { @@ -59,6 +60,7 @@ public: virtual void visitMDependency(const MDependency *dependency) = 0; virtual void visitMInheritance(const MInheritance *inheritance) = 0; virtual void visitMAssociation(const MAssociation *association) = 0; + virtual void visitMConnection(const MConnection *connection) = 0; }; } // namespace qmt diff --git a/src/libs/modelinglib/qmt/model/mvisitor.h b/src/libs/modelinglib/qmt/model/mvisitor.h index bce52be8d0..23390a47e3 100644 --- a/src/libs/modelinglib/qmt/model/mvisitor.h +++ b/src/libs/modelinglib/qmt/model/mvisitor.h @@ -41,6 +41,7 @@ class MRelation; class MDependency; class MInheritance; class MAssociation; +class MConnection; class MVisitor { @@ -59,6 +60,7 @@ public: virtual void visitMDependency(MDependency *dependency) = 0; virtual void visitMInheritance(MInheritance *inheritance) = 0; virtual void visitMAssociation(MAssociation *association) = 0; + virtual void visitMConnection(MConnection *connection) = 0; }; } // namespace qmt diff --git a/src/libs/modelinglib/qmt/model_controller/mchildrenvisitor.cpp b/src/libs/modelinglib/qmt/model_controller/mchildrenvisitor.cpp index b9edd7ff30..aed3f795f0 100644 --- a/src/libs/modelinglib/qmt/model_controller/mchildrenvisitor.cpp +++ b/src/libs/modelinglib/qmt/model_controller/mchildrenvisitor.cpp @@ -34,6 +34,7 @@ #include "qmt/model/mdependency.h" #include "qmt/model/minheritance.h" #include "qmt/model/massociation.h" +#include "qmt/model/mconnection.h" namespace qmt { @@ -102,4 +103,9 @@ void MChildrenVisitor::visitMAssociation(MAssociation *association) visitMRelation(association); } +void MChildrenVisitor::visitMConnection(MConnection *connection) +{ + visitMRelation(connection); +} + } // namespace qmt diff --git a/src/libs/modelinglib/qmt/model_controller/mchildrenvisitor.h b/src/libs/modelinglib/qmt/model_controller/mchildrenvisitor.h index 406febde8e..b36fc2104f 100644 --- a/src/libs/modelinglib/qmt/model_controller/mchildrenvisitor.h +++ b/src/libs/modelinglib/qmt/model_controller/mchildrenvisitor.h @@ -45,6 +45,7 @@ public: void visitMDependency(MDependency *dependency) override; void visitMInheritance(MInheritance *inheritance) override; void visitMAssociation(MAssociation *association) override; + void visitMConnection(MConnection *connection) override; }; } // namespace qmt diff --git a/src/libs/modelinglib/qmt/model_controller/mclonevisitor.cpp b/src/libs/modelinglib/qmt/model_controller/mclonevisitor.cpp index 505a7e6078..5c753b3173 100644 --- a/src/libs/modelinglib/qmt/model_controller/mclonevisitor.cpp +++ b/src/libs/modelinglib/qmt/model_controller/mclonevisitor.cpp @@ -35,6 +35,7 @@ #include "qmt/model/mitem.h" #include "qmt/model/mrelation.h" #include "qmt/model/massociation.h" +#include "qmt/model/mconnection.h" #include "qmt/model/mdependency.h" #include "qmt/model/minheritance.h" @@ -136,6 +137,13 @@ void MCloneVisitor::visitMAssociation(const MAssociation *association) visitMRelation(association); } +void MCloneVisitor::visitMConnection(const MConnection *connection) +{ + if (!m_cloned) + m_cloned = new MConnection(*connection); + visitMRelation(connection); +} + MCloneDeepVisitor::MCloneDeepVisitor() : m_cloned(0) { @@ -257,4 +265,11 @@ void MCloneDeepVisitor::visitMAssociation(const MAssociation *association) visitMRelation(association); } +void MCloneDeepVisitor::visitMConnection(const MConnection *connection) +{ + if (!m_cloned) + m_cloned = new MConnection(*connection); + visitMRelation(connection); +} + } // namespace qmt diff --git a/src/libs/modelinglib/qmt/model_controller/mclonevisitor.h b/src/libs/modelinglib/qmt/model_controller/mclonevisitor.h index 4d97acdd4f..437ed0d240 100644 --- a/src/libs/modelinglib/qmt/model_controller/mclonevisitor.h +++ b/src/libs/modelinglib/qmt/model_controller/mclonevisitor.h @@ -51,6 +51,7 @@ public: void visitMDependency(const MDependency *dependency) override; void visitMInheritance(const MInheritance *inheritance) override; void visitMAssociation(const MAssociation *association) override; + void visitMConnection(const MConnection *connection) override; private: MElement *m_cloned; @@ -75,6 +76,7 @@ public: void visitMDependency(const MDependency *dependency) override; void visitMInheritance(const MInheritance *inheritance) override; void visitMAssociation(const MAssociation *association) override; + void visitMConnection(const MConnection *connection) override; private: MElement *m_cloned; diff --git a/src/libs/modelinglib/qmt/model_controller/mflatassignmentvisitor.cpp b/src/libs/modelinglib/qmt/model_controller/mflatassignmentvisitor.cpp index c131bf2093..be6d99dbf0 100644 --- a/src/libs/modelinglib/qmt/model_controller/mflatassignmentvisitor.cpp +++ b/src/libs/modelinglib/qmt/model_controller/mflatassignmentvisitor.cpp @@ -34,6 +34,7 @@ #include "qmt/model/mdependency.h" #include "qmt/model/minheritance.h" #include "qmt/model/massociation.h" +#include "qmt/model/mconnection.h" namespace qmt { @@ -131,6 +132,17 @@ void MFlatAssignmentVisitor::visitMAssociation(const MAssociation *association) QMT_ASSERT(targetAssociation, return); targetAssociation->setEndA(association->endA()); targetAssociation->setEndB(association->endB()); + // TODO assign association class UID? +} + +void MFlatAssignmentVisitor::visitMConnection(const MConnection *connection) +{ + visitMRelation(connection); + auto targetConnection = dynamic_cast(m_target); + QMT_CHECK(targetConnection); + targetConnection->setCustomRelationId(connection->customRelationId()); + targetConnection->setEndA(connection->endA()); + targetConnection->setEndB(connection->endB()); } } // namespace qmt diff --git a/src/libs/modelinglib/qmt/model_controller/mflatassignmentvisitor.h b/src/libs/modelinglib/qmt/model_controller/mflatassignmentvisitor.h index 49d696fd92..f7e0e72da1 100644 --- a/src/libs/modelinglib/qmt/model_controller/mflatassignmentvisitor.h +++ b/src/libs/modelinglib/qmt/model_controller/mflatassignmentvisitor.h @@ -49,6 +49,7 @@ public: void visitMDependency(const MDependency *dependency) override; void visitMInheritance(const MInheritance *inheritance) override; void visitMAssociation(const MAssociation *association) override; + void visitMConnection(const MConnection *connection) override; private: MElement *m_target; diff --git a/src/libs/modelinglib/qmt/model_controller/mvoidvisitor.cpp b/src/libs/modelinglib/qmt/model_controller/mvoidvisitor.cpp index 67e93cf693..4e475ce3dd 100644 --- a/src/libs/modelinglib/qmt/model_controller/mvoidvisitor.cpp +++ b/src/libs/modelinglib/qmt/model_controller/mvoidvisitor.cpp @@ -35,6 +35,7 @@ #include "qmt/model/mitem.h" #include "qmt/model/mrelation.h" #include "qmt/model/massociation.h" +#include "qmt/model/mconnection.h" #include "qmt/model/mdependency.h" #include "qmt/model/minheritance.h" @@ -102,6 +103,11 @@ void MVoidVisitor::visitMAssociation(MAssociation *association) visitMRelation(association); } +void MVoidVisitor::visitMConnection(MConnection *connection) +{ + visitMRelation(connection); +} + void MVoidConstVisitor::visitMElement(const MElement *element) { Q_UNUSED(element); @@ -162,4 +168,9 @@ void MVoidConstVisitor::visitMAssociation(const MAssociation *association) visitMRelation(association); } +void MVoidConstVisitor::visitMConnection(const MConnection *connection) +{ + visitMRelation(connection); +} + } // namespace qmt diff --git a/src/libs/modelinglib/qmt/model_controller/mvoidvisitor.h b/src/libs/modelinglib/qmt/model_controller/mvoidvisitor.h index 34404adbb2..ff65a861ca 100644 --- a/src/libs/modelinglib/qmt/model_controller/mvoidvisitor.h +++ b/src/libs/modelinglib/qmt/model_controller/mvoidvisitor.h @@ -46,6 +46,7 @@ public: void visitMDependency(MDependency *dependency) override; void visitMInheritance(MInheritance *inheritance) override; void visitMAssociation(MAssociation *association) override; + void visitMConnection(MConnection *connection) override; }; class QMT_EXPORT MVoidConstVisitor : public MConstVisitor @@ -63,6 +64,7 @@ public: void visitMDependency(const MDependency *dependency) override; void visitMInheritance(const MInheritance *inheritance) override; void visitMAssociation(const MAssociation *association) override; + void visitMConnection(const MConnection *connection) override; }; } // namespace qmt diff --git a/src/libs/modelinglib/qmt/model_ui/treemodel.cpp b/src/libs/modelinglib/qmt/model_ui/treemodel.cpp index cc93ed14b7..bdedf995b9 100644 --- a/src/libs/modelinglib/qmt/model_ui/treemodel.cpp +++ b/src/libs/modelinglib/qmt/model_ui/treemodel.cpp @@ -36,6 +36,7 @@ #include "qmt/model/mitem.h" #include "qmt/model/mrelation.h" #include "qmt/model/massociation.h" +#include "qmt/model/mconnection.h" #include "qmt/model/mdependency.h" #include "qmt/model/minheritance.h" @@ -188,6 +189,15 @@ public: visitMRelation(association); } + void visitMConnection(const MConnection *connection) + { + QMT_CHECK(!m_item); + + static QIcon icon(QStringLiteral(":modelinglib/48x48/connection.ong")); + m_item = new ModelItem(icon, m_treeModel->createRelationLabel(connection)); + visitMRelation(connection); + } + private: TreeModel *m_treeModel = 0; TreeModel::ModelItem *m_item = 0; @@ -285,6 +295,11 @@ public: visitMRelation(association); } + void visitMConnection(const MConnection *connection) + { + visitMRelation(connection); + } + private: void updateObjectLabel(const MObject *object); void updateRelationLabel(const MRelation *relation); diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp index eef4ff9c14..dd299b3bb7 100644 --- a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp +++ b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp @@ -43,6 +43,7 @@ #include "qmt/model/mdependency.h" #include "qmt/model/minheritance.h" #include "qmt/model/massociation.h" +#include "qmt/model/mconnection.h" #include "qmt/diagram/delement.h" #include "qmt/diagram/dobject.h" @@ -55,12 +56,14 @@ #include "qmt/diagram/dinheritance.h" #include "qmt/diagram/ddependency.h" #include "qmt/diagram/dassociation.h" +#include "qmt/diagram/dconnection.h" #include "qmt/diagram/dannotation.h" #include "qmt/diagram/dboundary.h" // TODO move into better place #include "qmt/diagram_scene/items/stereotypedisplayvisitor.h" #include "qmt/stereotype/stereotypecontroller.h" +#include "qmt/stereotype/customrelation.h" #include "qmt/style/stylecontroller.h" #include "qmt/style/style.h" #include "qmt/style/objectvisuals.h" @@ -380,7 +383,7 @@ void PropertiesView::MView::visitMElement(const MElement *element) Q_UNUSED(element); prepare(); - if (m_stereotypeComboBox == 0) { + if (!m_stereotypeComboBox) { m_stereotypeComboBox = new QComboBox(m_topWidget); m_stereotypeComboBox->setEditable(true); m_stereotypeComboBox->setInsertPolicy(QComboBox::NoInsert); @@ -404,7 +407,7 @@ void PropertiesView::MView::visitMElement(const MElement *element) } } #ifdef SHOW_DEBUG_PROPERTIES - if (m_reverseEngineeredLabel == 0) { + if (!m_reverseEngineeredLabel) { m_reverseEngineeredLabel = new QLabel(m_topWidget); addRow(tr("Reverse engineered:"), m_reverseEngineeredLabel, "reverse engineered"); } @@ -418,7 +421,7 @@ void PropertiesView::MView::visitMObject(const MObject *object) visitMElement(object); QList selection = filter(m_modelElements); bool isSingleSelection = selection.size() == 1; - if (m_elementNameLineEdit == 0) { + if (!m_elementNameLineEdit) { m_elementNameLineEdit = new QLineEdit(m_topWidget); addRow(tr("Name:"), m_elementNameLineEdit, "name"); connect(m_elementNameLineEdit, &QLineEdit::textChanged, @@ -434,12 +437,12 @@ void PropertiesView::MView::visitMObject(const MObject *object) m_elementNameLineEdit->setEnabled(isSingleSelection); #ifdef SHOW_DEBUG_PROPERTIES - if (m_childrenLabel == 0) { + if (!m_childrenLabel) { m_childrenLabel = new QLabel(m_topWidget); addRow(tr("Children:"), m_childrenLabel, "children"); } m_childrenLabel->setText(QString::number(object->children().size())); - if (m_relationsLabel == 0) { + if (!m_relationsLabel) { m_relationsLabel = new QLabel(m_topWidget); addRow(tr("Relations:"), m_relationsLabel, "relations"); } @@ -462,7 +465,7 @@ void PropertiesView::MView::visitMClass(const MClass *klass) visitMObject(klass); QList selection = filter(m_modelElements); bool isSingleSelection = selection.size() == 1; - if (m_namespaceLineEdit == 0) { + if (!m_namespaceLineEdit) { m_namespaceLineEdit = new QLineEdit(m_topWidget); addRow(tr("Namespace:"), m_namespaceLineEdit, "namespace"); connect(m_namespaceLineEdit, &QLineEdit::textEdited, @@ -479,7 +482,7 @@ void PropertiesView::MView::visitMClass(const MClass *klass) m_namespaceLineEdit->setEnabled(false); } } - if (m_templateParametersLineEdit == 0) { + if (!m_templateParametersLineEdit) { m_templateParametersLineEdit = new QLineEdit(m_topWidget); addRow(tr("Template:"), m_templateParametersLineEdit, "template"); connect(m_templateParametersLineEdit, &QLineEdit::textChanged, @@ -496,7 +499,7 @@ void PropertiesView::MView::visitMClass(const MClass *klass) } if (m_templateParametersLineEdit->isEnabled() != isSingleSelection) m_templateParametersLineEdit->setEnabled(isSingleSelection); - if (m_classMembersStatusLabel == 0) { + if (!m_classMembersStatusLabel) { QMT_CHECK(!m_classMembersParseButton); m_classMembersStatusLabel = new QLabel(m_topWidget); m_classMembersParseButton = new QPushButton(tr("Clean Up"), m_topWidget); @@ -511,7 +514,7 @@ void PropertiesView::MView::visitMClass(const MClass *klass) } if (m_classMembersParseButton->isEnabled() != isSingleSelection) m_classMembersParseButton->setEnabled(isSingleSelection); - if (m_classMembersEdit == 0) { + if (!m_classMembersEdit) { m_classMembersEdit = new ClassMembersEdit(m_topWidget); m_classMembersEdit->setLineWrapMode(QPlainTextEdit::NoWrap); addRow(tr("Members:"), m_classMembersEdit, "members"); @@ -541,7 +544,7 @@ void PropertiesView::MView::visitMDiagram(const MDiagram *diagram) setTitle(m_modelElements, tr("Diagram"), tr("Diagrams")); visitMObject(diagram); #ifdef SHOW_DEBUG_PROPERTIES - if (m_diagramsLabel == 0) { + if (!m_diagramsLabel) { m_diagramsLabel = new QLabel(m_topWidget); addRow(tr("Elements:"), m_diagramsLabel, "elements"); } @@ -562,7 +565,7 @@ void PropertiesView::MView::visitMItem(const MItem *item) QList selection = filter(m_modelElements); bool isSingleSelection = selection.size() == 1; if (item->isVarietyEditable()) { - if (m_itemVarietyEdit == 0) { + if (!m_itemVarietyEdit) { m_itemVarietyEdit = new QLineEdit(m_topWidget); addRow(tr("Variety:"), m_itemVarietyEdit, "variety"); connect(m_itemVarietyEdit, &QLineEdit::textChanged, @@ -584,7 +587,7 @@ void PropertiesView::MView::visitMRelation(const MRelation *relation) visitMElement(relation); QList selection = filter(m_modelElements); bool isSingleSelection = selection.size() == 1; - if (m_elementNameLineEdit == 0) { + if (!m_elementNameLineEdit) { m_elementNameLineEdit = new QLineEdit(m_topWidget); addRow(tr("Name:"), m_elementNameLineEdit, "name"); connect(m_elementNameLineEdit, &QLineEdit::textChanged, @@ -612,7 +615,7 @@ void PropertiesView::MView::visitMDependency(const MDependency *dependency) visitMRelation(dependency); QList selection = filter(m_modelElements); bool isSingleSelection = selection.size() == 1; - if (m_directionSelector == 0) { + if (!m_directionSelector) { m_directionSelector = new QComboBox(m_topWidget); m_directionSelector->addItems(QStringList({ "->", "<-", "<->" })); addRow(tr("Direction:"), m_directionSelector, "direction"); @@ -650,11 +653,11 @@ void PropertiesView::MView::visitMAssociation(const MAssociation *association) visitMRelation(association); QList selection = filter(m_modelElements); bool isSingleSelection = selection.size() == 1; - if (m_endALabel == 0) { + if (!m_endALabel) { m_endALabel = new QLabel(QStringLiteral("") + m_endAName + QStringLiteral("")); addRow(m_endALabel, "end a"); } - if (m_endAEndName == 0) { + if (!m_endAEndName) { m_endAEndName = new QLineEdit(m_topWidget); addRow(tr("Role:"), m_endAEndName, "role a"); connect(m_endAEndName, &QLineEdit::textChanged, @@ -668,7 +671,7 @@ void PropertiesView::MView::visitMAssociation(const MAssociation *association) } if (m_endAEndName->isEnabled() != isSingleSelection) m_endAEndName->setEnabled(isSingleSelection); - if (m_endACardinality == 0) { + if (!m_endACardinality) { m_endACardinality = new QLineEdit(m_topWidget); addRow(tr("Cardinality:"), m_endACardinality, "cardinality a"); connect(m_endACardinality, &QLineEdit::textChanged, @@ -682,7 +685,7 @@ void PropertiesView::MView::visitMAssociation(const MAssociation *association) } if (m_endACardinality->isEnabled() != isSingleSelection) m_endACardinality->setEnabled(isSingleSelection); - if (m_endANavigable == 0) { + if (!m_endANavigable) { m_endANavigable = new QCheckBox(tr("Navigable"), m_topWidget); addRow(QString(), m_endANavigable, "navigable a"); connect(m_endANavigable, &QAbstractButton::clicked, @@ -696,7 +699,7 @@ void PropertiesView::MView::visitMAssociation(const MAssociation *association) } if (m_endANavigable->isEnabled() != isSingleSelection) m_endANavigable->setEnabled(isSingleSelection); - if (m_endAKind == 0) { + if (!m_endAKind) { m_endAKind = new QComboBox(m_topWidget); m_endAKind->addItems({ tr("Association"), tr("Aggregation"), tr("Composition") }); addRow(tr("Relationship:"), m_endAKind, "relationship a"); @@ -715,11 +718,11 @@ void PropertiesView::MView::visitMAssociation(const MAssociation *association) if (m_endAKind->isEnabled() != isSingleSelection) m_endAKind->setEnabled(isSingleSelection); - if (m_endBLabel == 0) { + if (!m_endBLabel) { m_endBLabel = new QLabel(QStringLiteral("") + m_endBName + QStringLiteral("")); addRow(m_endBLabel, "end b"); } - if (m_endBEndName == 0) { + if (!m_endBEndName) { m_endBEndName = new QLineEdit(m_topWidget); addRow(tr("Role:"), m_endBEndName, "role b"); connect(m_endBEndName, &QLineEdit::textChanged, @@ -733,7 +736,7 @@ void PropertiesView::MView::visitMAssociation(const MAssociation *association) } if (m_endBEndName->isEnabled() != isSingleSelection) m_endBEndName->setEnabled(isSingleSelection); - if (m_endBCardinality == 0) { + if (!m_endBCardinality) { m_endBCardinality = new QLineEdit(m_topWidget); addRow(tr("Cardinality:"), m_endBCardinality, "cardinality b"); connect(m_endBCardinality, &QLineEdit::textChanged, @@ -747,7 +750,7 @@ void PropertiesView::MView::visitMAssociation(const MAssociation *association) } if (m_endBCardinality->isEnabled() != isSingleSelection) m_endBCardinality->setEnabled(isSingleSelection); - if (m_endBNavigable == 0) { + if (!m_endBNavigable) { m_endBNavigable = new QCheckBox(tr("Navigable"), m_topWidget); addRow(QString(), m_endBNavigable, "navigable b"); connect(m_endBNavigable, &QAbstractButton::clicked, @@ -761,7 +764,7 @@ void PropertiesView::MView::visitMAssociation(const MAssociation *association) } if (m_endBNavigable->isEnabled() != isSingleSelection) m_endBNavigable->setEnabled(isSingleSelection); - if (m_endBKind == 0) { + if (!m_endBKind) { m_endBKind = new QComboBox(m_topWidget); m_endBKind->addItems({ tr("Association"), tr("Aggregation"), tr("Composition") }); addRow(tr("Relationship:"), m_endBKind, "relationship b"); @@ -781,6 +784,107 @@ void PropertiesView::MView::visitMAssociation(const MAssociation *association) m_endBKind->setEnabled(isSingleSelection); } +void PropertiesView::MView::visitMConnection(const MConnection *connection) +{ + setTitle(connection, m_modelElements, tr("Connection"), tr("Connections")); + visitMRelation(connection); + QList selection = filter(m_modelElements); + const bool isSingleSelection = selection.size() == 1; + if (!m_endALabel) { + m_endALabel = new QLabel(QStringLiteral("") + m_endAName + QStringLiteral("")); + addRow(m_endALabel, "end a"); + } + if (!m_endAEndName) { + m_endAEndName = new QLineEdit(m_topWidget); + addRow(tr("Role:"), m_endAEndName, "role a"); + connect(m_endAEndName, &QLineEdit::textChanged, + this, &PropertiesView::MView::onConnectionEndANameChanged); + } + if (isSingleSelection) { + if (connection->endA().name() != m_endAEndName->text() && !m_endAEndName->hasFocus()) + m_endAEndName->setText(connection->endA().name()); + } else { + m_endAEndName->clear(); + } + if (m_endAEndName->isEnabled() != isSingleSelection) + m_endAEndName->setEnabled(isSingleSelection); + if (!m_endACardinality) { + m_endACardinality = new QLineEdit(m_topWidget); + addRow(tr("Cardinality:"), m_endACardinality, "cardinality a"); + connect(m_endACardinality, &QLineEdit::textChanged, + this, &PropertiesView::MView::onConnectionEndACardinalityChanged); + } + if (isSingleSelection) { + if (connection->endA().cardinality() != m_endACardinality->text() && !m_endACardinality->hasFocus()) + m_endACardinality->setText(connection->endA().cardinality()); + } else { + m_endACardinality->clear(); + } + if (m_endACardinality->isEnabled() != isSingleSelection) + m_endACardinality->setEnabled(isSingleSelection); + if (!m_endANavigable) { + m_endANavigable = new QCheckBox(tr("Navigable"), m_topWidget); + addRow(QString(), m_endANavigable, "navigable a"); + connect(m_endANavigable, &QAbstractButton::clicked, + this, &PropertiesView::MView::onConnectionEndANavigableChanged); + } + if (isSingleSelection) { + if (connection->endA().isNavigable() != m_endANavigable->isChecked()) + m_endANavigable->setChecked(connection->endA().isNavigable()); + } else { + m_endANavigable->setChecked(false); + } + if (m_endANavigable->isEnabled() != isSingleSelection) + m_endANavigable->setEnabled(isSingleSelection); + + if (!m_endBLabel) { + m_endBLabel = new QLabel(QStringLiteral("") + m_endBName + QStringLiteral("")); + addRow(m_endBLabel, "end b"); + } + if (!m_endBEndName) { + m_endBEndName = new QLineEdit(m_topWidget); + addRow(tr("Role:"), m_endBEndName, "role b"); + connect(m_endBEndName, &QLineEdit::textChanged, + this, &PropertiesView::MView::onConnectionEndBNameChanged); + } + if (isSingleSelection) { + if (connection->endB().name() != m_endBEndName->text() && !m_endBEndName->hasFocus()) + m_endBEndName->setText(connection->endB().name()); + } else { + m_endBEndName->clear(); + } + if (m_endBEndName->isEnabled() != isSingleSelection) + m_endBEndName->setEnabled(isSingleSelection); + if (!m_endBCardinality) { + m_endBCardinality = new QLineEdit(m_topWidget); + addRow(tr("Cardinality:"), m_endBCardinality, "cardinality b"); + connect(m_endBCardinality, &QLineEdit::textChanged, + this, &PropertiesView::MView::onConnectionEndBCardinalityChanged); + } + if (isSingleSelection) { + if (connection->endB().cardinality() != m_endBCardinality->text() && !m_endBCardinality->hasFocus()) + m_endBCardinality->setText(connection->endB().cardinality()); + } else { + m_endBCardinality->clear(); + } + if (m_endBCardinality->isEnabled() != isSingleSelection) + m_endBCardinality->setEnabled(isSingleSelection); + if (!m_endBNavigable) { + m_endBNavigable = new QCheckBox(tr("Navigable"), m_topWidget); + addRow(QString(), m_endBNavigable, "navigable b"); + connect(m_endBNavigable, &QAbstractButton::clicked, + this, &PropertiesView::MView::onConnectionEndBNavigableChanged); + } + if (isSingleSelection) { + if (connection->endB().isNavigable() != m_endBNavigable->isChecked()) + m_endBNavigable->setChecked(connection->endB().isNavigable()); + } else { + m_endBNavigable->setChecked(false); + } + if (m_endBNavigable->isEnabled() != isSingleSelection) + m_endBNavigable->setEnabled(isSingleSelection); +} + void PropertiesView::MView::visitDElement(const DElement *element) { Q_UNUSED(element); @@ -789,7 +893,7 @@ void PropertiesView::MView::visitDElement(const DElement *element) m_propertiesTitle.clear(); m_modelElements.at(0)->accept(this); #ifdef SHOW_DEBUG_PROPERTIES - if (m_separatorLine == 0) { + if (!m_separatorLine) { m_separatorLine = new QFrame(m_topWidget); m_separatorLine->setFrameShape(QFrame::StyledPanel); m_separatorLine->setLineWidth(2); @@ -806,7 +910,7 @@ void PropertiesView::MView::visitDObject(const DObject *object) { visitDElement(object); #ifdef SHOW_DEBUG_PROPERTIES - if (m_posRectLabel == 0) { + if (!m_posRectLabel) { m_posRectLabel = new QLabel(m_topWidget); addRow(tr("Position and size:"), m_posRectLabel, "position and size"); } @@ -818,7 +922,7 @@ void PropertiesView::MView::visitDObject(const DObject *object) .arg(object->rect().right()) .arg(object->rect().bottom())); #endif - if (m_autoSizedCheckbox == 0) { + if (!m_autoSizedCheckbox) { m_autoSizedCheckbox = new QCheckBox(tr("Auto sized"), m_topWidget); addRow(QString(), m_autoSizedCheckbox, "auto size"); connect(m_autoSizedCheckbox, &QAbstractButton::clicked, @@ -831,7 +935,7 @@ void PropertiesView::MView::visitDObject(const DObject *object) else m_autoSizedCheckbox->setChecked(false); } - if (m_visualPrimaryRoleSelector == 0) { + if (!m_visualPrimaryRoleSelector) { m_visualPrimaryRoleSelector = new PaletteBox(m_topWidget); setPrimaryRolePalette(m_styleElementType, DObject::PrimaryRoleCustom1, QColor()); setPrimaryRolePalette(m_styleElementType, DObject::PrimaryRoleCustom2, QColor()); @@ -860,7 +964,7 @@ void PropertiesView::MView::visitDObject(const DObject *object) else m_visualPrimaryRoleSelector->setCurrentIndex(-1); } - if (m_visualSecondaryRoleSelector == 0) { + if (!m_visualSecondaryRoleSelector) { m_visualSecondaryRoleSelector = new QComboBox(m_topWidget); m_visualSecondaryRoleSelector->addItems({ tr("Normal"), tr("Lighter"), tr("Darker"), tr("Soften"), tr("Outline") }); @@ -875,7 +979,7 @@ void PropertiesView::MView::visitDObject(const DObject *object) else m_visualSecondaryRoleSelector->setCurrentIndex(-1); } - if (m_visualEmphasizedCheckbox == 0) { + if (!m_visualEmphasizedCheckbox) { m_visualEmphasizedCheckbox = new QCheckBox(tr("Emphasized"), m_topWidget); addRow(QString(), m_visualEmphasizedCheckbox, "emphasized"); connect(m_visualEmphasizedCheckbox, &QAbstractButton::clicked, @@ -888,7 +992,7 @@ void PropertiesView::MView::visitDObject(const DObject *object) else m_visualEmphasizedCheckbox->setChecked(false); } - if (m_stereotypeDisplaySelector == 0) { + if (!m_stereotypeDisplaySelector) { m_stereotypeDisplaySelector = new QComboBox(m_topWidget); m_stereotypeDisplaySelector->addItems({ tr("Smart"), tr("None"), tr("Label"), tr("Decoration"), tr("Icon") }); @@ -904,7 +1008,7 @@ void PropertiesView::MView::visitDObject(const DObject *object) m_stereotypeDisplaySelector->setCurrentIndex(-1); } #ifdef SHOW_DEBUG_PROPERTIES - if (m_depthLabel == 0) { + if (!m_depthLabel) { m_depthLabel = new QLabel(m_topWidget); addRow(tr("Depth:"), m_depthLabel, "depth"); } @@ -926,7 +1030,7 @@ void PropertiesView::MView::visitDClass(const DClass *klass) setStereotypeIconElement(StereotypeIcon::ElementClass); setStyleElementType(StyleEngine::TypeClass); visitDObject(klass); - if (m_templateDisplaySelector == 0) { + if (!m_templateDisplaySelector) { m_templateDisplaySelector = new QComboBox(m_topWidget); m_templateDisplaySelector->addItems({ tr("Smart"), tr("Box"), tr("Angle Brackets") }); addRow(tr("Template display:"), m_templateDisplaySelector, "template display"); @@ -940,7 +1044,7 @@ void PropertiesView::MView::visitDClass(const DClass *klass) else m_templateDisplaySelector->setCurrentIndex(-1); } - if (m_showAllMembersCheckbox == 0) { + if (!m_showAllMembersCheckbox) { m_showAllMembersCheckbox = new QCheckBox(tr("Show members"), m_topWidget); addRow(QString(), m_showAllMembersCheckbox, "show members"); connect(m_showAllMembersCheckbox, &QAbstractButton::clicked, @@ -961,7 +1065,7 @@ void PropertiesView::MView::visitDComponent(const DComponent *component) setStereotypeIconElement(StereotypeIcon::ElementComponent); setStyleElementType(StyleEngine::TypeComponent); visitDObject(component); - if (m_plainShapeCheckbox == 0) { + if (!m_plainShapeCheckbox) { m_plainShapeCheckbox = new QCheckBox(tr("Plain shape"), m_topWidget); addRow(QString(), m_plainShapeCheckbox, "plain shape"); connect(m_plainShapeCheckbox, &QAbstractButton::clicked, @@ -992,7 +1096,7 @@ void PropertiesView::MView::visitDItem(const DItem *item) QList selection = filter(m_diagramElements); bool isSingleSelection = selection.size() == 1; if (item->isShapeEditable()) { - if (m_itemShapeEdit == 0) { + if (!m_itemShapeEdit) { m_itemShapeEdit = new QLineEdit(m_topWidget); addRow(tr("Shape:"), m_itemShapeEdit, "shape"); connect(m_itemShapeEdit, &QLineEdit::textChanged, @@ -1032,11 +1136,17 @@ void PropertiesView::MView::visitDAssociation(const DAssociation *association) visitDRelation(association); } +void PropertiesView::MView::visitDConnection(const DConnection *connection) +{ + setTitle(m_diagramElements, tr("Connection"), tr("Connections")); + visitDRelation(connection); +} + void PropertiesView::MView::visitDAnnotation(const DAnnotation *annotation) { setTitle(m_diagramElements, tr("Annotation"), tr("Annotations")); visitDElement(annotation); - if (m_annotationAutoWidthCheckbox == 0) { + if (!m_annotationAutoWidthCheckbox) { m_annotationAutoWidthCheckbox = new QCheckBox(tr("Auto width"), m_topWidget); addRow(QString(), m_annotationAutoWidthCheckbox, "auto width"); connect(m_annotationAutoWidthCheckbox, &QAbstractButton::clicked, @@ -1049,7 +1159,7 @@ void PropertiesView::MView::visitDAnnotation(const DAnnotation *annotation) else m_annotationAutoWidthCheckbox->setChecked(false); } - if (m_annotationVisualRoleSelector == 0) { + if (!m_annotationVisualRoleSelector) { m_annotationVisualRoleSelector = new QComboBox(m_topWidget); m_annotationVisualRoleSelector->addItems(QStringList({ tr("Normal"), tr("Title"), tr("Subtitle"), tr("Emphasized"), @@ -1207,6 +1317,48 @@ void PropertiesView::MView::onAssociationEndBKindChanged(int kindIndex) &MAssociationEnd::kind, &MAssociationEnd::setKind); } +void PropertiesView::MView::onConnectionEndANameChanged(const QString &name) +{ + assignEmbeddedModelElement( + m_modelElements, SelectionSingle, name, &MConnection::endA, &MConnection::setEndA, + &MConnectionEnd::name, &MConnectionEnd::setName); +} + +void PropertiesView::MView::onConnectionEndACardinalityChanged(const QString &cardinality) +{ + assignEmbeddedModelElement( + m_modelElements, SelectionSingle, cardinality, &MConnection::endA, &MConnection::setEndA, + &MConnectionEnd::cardinality, &MConnectionEnd::setCardinality); +} + +void PropertiesView::MView::onConnectionEndANavigableChanged(bool navigable) +{ + assignEmbeddedModelElement( + m_modelElements, SelectionSingle, navigable, &MConnection::endA, &MConnection::setEndA, + &MConnectionEnd::isNavigable, &MConnectionEnd::setNavigable); +} + +void PropertiesView::MView::onConnectionEndBNameChanged(const QString &name) +{ + assignEmbeddedModelElement( + m_modelElements, SelectionSingle, name, &MConnection::endB, &MConnection::setEndB, + &MConnectionEnd::name, &MConnectionEnd::setName); +} + +void PropertiesView::MView::onConnectionEndBCardinalityChanged(const QString &cardinality) +{ + assignEmbeddedModelElement( + m_modelElements, SelectionSingle, cardinality, &MConnection::endB, &MConnection::setEndB, + &MConnectionEnd::cardinality, &MConnectionEnd::setCardinality); +} + +void PropertiesView::MView::onConnectionEndBNavigableChanged(bool navigable) +{ + assignEmbeddedModelElement( + m_modelElements, SelectionSingle, navigable, &MConnection::endB, &MConnection::setEndB, + &MConnectionEnd::isNavigable, &MConnectionEnd::setNavigable); +} + void PropertiesView::MView::onAutoSizedChanged(bool autoSized) { assignModelElement(m_diagramElements, SelectionMulti, autoSized, @@ -1284,12 +1436,12 @@ void PropertiesView::MView::onAnnotationVisualRoleChanged(int visualRoleIndex) void PropertiesView::MView::prepare() { QMT_CHECK(!m_propertiesTitle.isEmpty()); - if (m_topWidget == 0) { + if (!m_topWidget) { m_topWidget = new QWidget(); m_topLayout = new QFormLayout(m_topWidget); m_topWidget->setLayout(m_topLayout); } - if (m_classNameLabel == 0) { + if (!m_classNameLabel) { m_classNameLabel = new QLabel(); m_topLayout->addRow(m_classNameLabel); m_rowToId.append("title"); @@ -1372,26 +1524,54 @@ template void PropertiesView::MView::setTitle(const MItem *item, const QList &elements, const QString &singularTitle, const QString &pluralTitle) { - if (m_propertiesTitle.isEmpty()) { - QList filtered = filter(elements); - if (filtered.size() == elements.size()) { - if (elements.size() == 1) { - if (item && !item->isVarietyEditable()) { - QString stereotypeIconId = m_propertiesView->stereotypeController() + if (!m_propertiesTitle.isEmpty()) + return; + QList filtered = filter(elements); + if (filtered.size() == elements.size()) { + if (elements.size() == 1) { + if (item && !item->isVarietyEditable()) { + QString stereotypeIconId = m_propertiesView->stereotypeController() ->findStereotypeIconId(StereotypeIcon::ElementItem, QStringList(item->variety())); - if (!stereotypeIconId.isEmpty()) { - StereotypeIcon stereotypeIcon = m_propertiesView->stereotypeController()->findStereotypeIcon(stereotypeIconId); - m_propertiesTitle = stereotypeIcon.title(); - } + if (!stereotypeIconId.isEmpty()) { + StereotypeIcon stereotypeIcon = m_propertiesView->stereotypeController()->findStereotypeIcon(stereotypeIconId); + m_propertiesTitle = stereotypeIcon.title(); } - if (m_propertiesTitle.isEmpty()) - m_propertiesTitle = singularTitle; - } else { - m_propertiesTitle = pluralTitle; } + if (m_propertiesTitle.isEmpty()) + m_propertiesTitle = singularTitle; } else { - m_propertiesTitle = QCoreApplication::translate("qmt::PropertiesView::MView", "Multi-Selection"); + m_propertiesTitle = pluralTitle; } + } else { + m_propertiesTitle = QCoreApplication::translate("qmt::PropertiesView::MView", "Multi-Selection"); + } +} + +template +void PropertiesView::MView::setTitle(const MConnection *connection, const QList &elements, + const QString &singularTitle, const QString &pluralTitle) +{ + if (!m_propertiesTitle.isEmpty()) + return; + QList filtered = filter(elements); + if (filtered.size() == elements.size()) { + if (elements.size() == 1) { + if (connection) { + CustomRelation customRelation = m_propertiesView->stereotypeController() + ->findCustomRelation(connection->customRelationId()); + if (!customRelation.isNull()) { + m_propertiesTitle = customRelation.title(); + if (m_propertiesTitle.isEmpty()) + m_propertiesTitle = connection->customRelationId(); + } + } + if (m_propertiesTitle.isEmpty()) + m_propertiesTitle = singularTitle; + } else { + m_propertiesTitle = pluralTitle; + } + } else { + m_propertiesTitle = QCoreApplication::translate("qmt::PropertiesView::MView", "Multi-Selection"); } } diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.h b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.h index 36418cbd9c..4c6794fb7f 100644 --- a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.h +++ b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.h @@ -78,6 +78,7 @@ public: void visitMDependency(const MDependency *dependency) override; void visitMInheritance(const MInheritance *inheritance) override; void visitMAssociation(const MAssociation *association) override; + void visitMConnection(const MConnection *connection) override; void visitDElement(const DElement *element) override; void visitDObject(const DObject *object) override; @@ -90,6 +91,7 @@ public: void visitDInheritance(const DInheritance *inheritance) override; void visitDDependency(const DDependency *dependency) override; void visitDAssociation(const DAssociation *association) override; + void visitDConnection(const DConnection *connection) override; void visitDAnnotation(const DAnnotation *annotation) override; void visitDBoundary(const DBoundary *boundary) override; @@ -116,6 +118,12 @@ protected: void onAssociationEndBCardinalityChanged(const QString &cardinality); void onAssociationEndBNavigableChanged(bool navigable); void onAssociationEndBKindChanged(int kindIndex); + void onConnectionEndANameChanged(const QString &name); + void onConnectionEndACardinalityChanged(const QString &cardinality); + void onConnectionEndANavigableChanged(bool navigable); + void onConnectionEndBNameChanged(const QString &name); + void onConnectionEndBCardinalityChanged(const QString &cardinality); + void onConnectionEndBNavigableChanged(bool navigable); void onAutoSizedChanged(bool autoSized); void onVisualPrimaryRoleChanged(int visualRoleIndex); void onVisualSecondaryRoleChanged(int visualRoleIndex); @@ -141,6 +149,9 @@ protected: template void setTitle(const MItem *item, const QList &elements, const QString &singularTitle, const QString &pluralTitle); + template + void setTitle(const MConnection *connection, const QList &elements, + const QString &singularTitle, const QString &pluralTitle); void setStereotypeIconElement(StereotypeIcon::Element stereotypeElement); void setStyleElementType(StyleEngine::ElementType elementType); void setPrimaryRolePalette(StyleEngine::ElementType elementType, diff --git a/src/libs/modelinglib/qmt/qmt.pri b/src/libs/modelinglib/qmt/qmt.pri index ec98011fe2..8d27d4e9e9 100644 --- a/src/libs/modelinglib/qmt/qmt.pri +++ b/src/libs/modelinglib/qmt/qmt.pri @@ -27,6 +27,7 @@ HEADERS += \ $$PWD/diagram/dboundary.h \ $$PWD/diagram/dclass.h \ $$PWD/diagram/dcomponent.h \ + $$PWD/diagram/dconnection.h \ $$PWD/diagram/dconstvisitor.h \ $$PWD/diagram/ddependency.h \ $$PWD/diagram/ddiagram.h \ @@ -55,6 +56,7 @@ HEADERS += \ $$PWD/diagram_scene/items/boundaryitem.h \ $$PWD/diagram_scene/items/classitem.h \ $$PWD/diagram_scene/items/componentitem.h \ + $$PWD/diagram_scene/items/connectionitem.h \ $$PWD/diagram_scene/items/diagramitem.h \ $$PWD/diagram_scene/items/itemitem.h \ $$PWD/diagram_scene/items/objectitem.h \ @@ -103,6 +105,7 @@ HEADERS += \ $$PWD/model/mclass.h \ $$PWD/model/mclassmember.h \ $$PWD/model/mcomponent.h \ + $$PWD/model/mconnection.h \ $$PWD/model/mconstvisitor.h \ $$PWD/model/mdependency.h \ $$PWD/model/mdiagram.h \ @@ -180,6 +183,7 @@ SOURCES += \ $$PWD/diagram/dboundary.cpp \ $$PWD/diagram/dclass.cpp \ $$PWD/diagram/dcomponent.cpp \ + $$PWD/diagram/dconnection.cpp \ $$PWD/diagram/ddependency.cpp \ $$PWD/diagram/ddiagram.cpp \ $$PWD/diagram/delement.cpp \ @@ -196,6 +200,7 @@ SOURCES += \ $$PWD/diagram_scene/items/boundaryitem.cpp \ $$PWD/diagram_scene/items/classitem.cpp \ $$PWD/diagram_scene/items/componentitem.cpp \ + $$PWD/diagram_scene/items/connectionitem.cpp \ $$PWD/diagram_scene/items/diagramitem.cpp \ $$PWD/diagram_scene/items/itemitem.cpp \ $$PWD/diagram_scene/items/objectitem.cpp \ @@ -235,6 +240,7 @@ SOURCES += \ $$PWD/model/mclass.cpp \ $$PWD/model/mclassmember.cpp \ $$PWD/model/mcomponent.cpp \ + $$PWD/model/mconnection.cpp \ $$PWD/model/mdependency.cpp \ $$PWD/model/mdiagram.cpp \ $$PWD/model/melement.cpp \ diff --git a/src/libs/modelinglib/qmt/serializer/diagramserializer.cpp b/src/libs/modelinglib/qmt/serializer/diagramserializer.cpp index c58eaca70e..01d02d8729 100644 --- a/src/libs/modelinglib/qmt/serializer/diagramserializer.cpp +++ b/src/libs/modelinglib/qmt/serializer/diagramserializer.cpp @@ -41,6 +41,7 @@ #include "qmt/diagram/dinheritance.h" #include "qmt/diagram/ddependency.h" #include "qmt/diagram/dassociation.h" +#include "qmt/diagram/dconnection.h" #include "qmt/diagram/dannotation.h" #include "qmt/diagram/dboundary.h" @@ -329,6 +330,39 @@ inline void Access::serialize(Archive &archive, DAssociat QARK_ACCESS_SPECIALIZE(QXmlInArchive, QXmlOutArchive, DAssociation) +// DConnection + +QARK_REGISTER_TYPE_NAME(DConnectionEnd, "DConnectionEnd") +QARK_ACCESS_SERIALIZE(DConnectionEnd) + +template +inline void Access::serialize(Archive &archive, DConnectionEnd &connectionEnd) +{ + archive || tag(connectionEnd) + || attr(QStringLiteral("name"), connectionEnd, &DConnectionEnd::name, &DConnectionEnd::setName) + || attr(QStringLiteral("cradinality"), connectionEnd, &DConnectionEnd::cardinality, &DConnectionEnd::setCardinatlity) + || attr(QStringLiteral("navigable"), connectionEnd, &DConnectionEnd::isNavigable, &DConnectionEnd::setNavigable) + || end; +} + +QARK_REGISTER_TYPE_NAME(DConnection, "DConnection") +QARK_REGISTER_DERIVED_CLASS(QXmlInArchive, QXmlOutArchive, DConnection, DElement) +QARK_REGISTER_DERIVED_CLASS(QXmlInArchive, QXmlOutArchive, DConnection, DRelation) +QARK_ACCESS_SERIALIZE(DConnection) + +template +inline void Access::serialize(Archive &archive, DConnection &connection) +{ + archive || tag(connection) + || base(connection) + || attr(QStringLiteral("custom-relation"), connection, &DConnection::customRelationId, &DConnection::setCustomRelationId) + || attr(QStringLiteral("a"), connection, &DConnection::endA, &DConnection::setEndA) + || attr(QStringLiteral("b"), connection, &DConnection::endB, &DConnection::setEndB) + || end; +} + +QARK_ACCESS_SPECIALIZE(QXmlInArchive, QXmlOutArchive, DConnection) + // DAnnotation QARK_REGISTER_TYPE_NAME(DAnnotation, "DAnnotation") diff --git a/src/libs/modelinglib/qmt/serializer/modelserializer.cpp b/src/libs/modelinglib/qmt/serializer/modelserializer.cpp index e141c050e9..b6ea080a2c 100644 --- a/src/libs/modelinglib/qmt/serializer/modelserializer.cpp +++ b/src/libs/modelinglib/qmt/serializer/modelserializer.cpp @@ -41,6 +41,7 @@ #include "qmt/model/mdependency.h" #include "qmt/model/massociation.h" #include "qmt/model/minheritance.h" +#include "qmt/model/mconnection.h" #include "qmt/diagram/delement.h" @@ -344,4 +345,37 @@ inline void Access::serialize(Archive &archive, MAssociat QARK_ACCESS_SPECIALIZE(QXmlInArchive, QXmlOutArchive, MAssociation) +// MConnection + +QARK_REGISTER_TYPE_NAME(MConnectionEnd, "MConnectionEnd") +QARK_ACCESS_SERIALIZE(MConnectionEnd) + +template +inline void Access::serialize(Archive &archive, MConnectionEnd &connectionEnd) +{ + archive || tag(connectionEnd) + || attr(QStringLiteral("name"), connectionEnd, &MConnectionEnd::name, &MConnectionEnd::setName) + || attr(QStringLiteral("cardinality"), connectionEnd, &MConnectionEnd::cardinality, &MConnectionEnd::setCardinality) + || attr(QStringLiteral("navigable"), connectionEnd, &MConnectionEnd::isNavigable, &MConnectionEnd::setNavigable) + || end; +} + +QARK_REGISTER_TYPE_NAME(MConnection, "MConnection") +QARK_REGISTER_DERIVED_CLASS(QXmlInArchive, QXmlOutArchive, MConnection, MElement) +QARK_REGISTER_DERIVED_CLASS(QXmlInArchive, QXmlOutArchive, MConnection, MRelation) +QARK_ACCESS_SERIALIZE(MConnection) + +template +inline void Access::serialize(Archive &archive, MConnection &connection) +{ + archive || tag(connection) + || base(connection) + || attr(QStringLiteral("custom-relation"), connection, &MConnection::customRelationId, &MConnection::setCustomRelationId) + || attr(QStringLiteral("a"), connection, &MConnection::endA, &MConnection::setEndA) + || attr(QStringLiteral("b"), connection, &MConnection::endB, &MConnection::setEndB) + || end; +} + +QARK_ACCESS_SPECIALIZE(QXmlInArchive, QXmlOutArchive, MConnection) + } // namespace qark diff --git a/src/libs/modelinglib/qmt/tasks/alignonrastervisitor.cpp b/src/libs/modelinglib/qmt/tasks/alignonrastervisitor.cpp index 5a6fa6c381..eeef4c866b 100644 --- a/src/libs/modelinglib/qmt/tasks/alignonrastervisitor.cpp +++ b/src/libs/modelinglib/qmt/tasks/alignonrastervisitor.cpp @@ -31,6 +31,7 @@ #include "qmt/diagram/dboundary.h" #include "qmt/diagram/dclass.h" #include "qmt/diagram/dcomponent.h" +#include "qmt/diagram/dconnection.h" #include "qmt/diagram/ddependency.h" #include "qmt/diagram/ddiagram.h" #include "qmt/diagram/ditem.h" @@ -135,6 +136,11 @@ void AlignOnRasterVisitor::visitDAssociation(DAssociation *association) visitDRelation(association); } +void AlignOnRasterVisitor::visitDConnection(DConnection *connection) +{ + visitDRelation(connection); +} + void AlignOnRasterVisitor::visitDAnnotation(DAnnotation *annotation) { IMoveable *moveable = m_sceneInspector->moveable(annotation, m_diagram); diff --git a/src/libs/modelinglib/qmt/tasks/alignonrastervisitor.h b/src/libs/modelinglib/qmt/tasks/alignonrastervisitor.h index 994cab48c3..42f9565ebd 100644 --- a/src/libs/modelinglib/qmt/tasks/alignonrastervisitor.h +++ b/src/libs/modelinglib/qmt/tasks/alignonrastervisitor.h @@ -55,6 +55,7 @@ public: void visitDInheritance(DInheritance *inheritance) override; void visitDDependency(DDependency *dependency) override; void visitDAssociation(DAssociation *association) override; + void visitDConnection(DConnection *connection) override; void visitDAnnotation(DAnnotation *annotation) override; void visitDBoundary(DBoundary *boundary) override; diff --git a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp index 78297bb312..b241418f57 100644 --- a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp +++ b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp @@ -37,6 +37,7 @@ #include "qmt/diagram/ditem.h" #include "qmt/diagram/drelation.h" #include "qmt/diagram/dassociation.h" +#include "qmt/diagram/dconnection.h" #include "qmt/diagram_ui/diagram_mime_types.h" #include "qmt/model_controller/modelcontroller.h" #include "qmt/model_controller/mselection.h" @@ -45,6 +46,7 @@ #include "qmt/model/mcanvasdiagram.h" #include "qmt/model/mclass.h" #include "qmt/model/mcomponent.h" +#include "qmt/model/mconnection.h" #include "qmt/model/mdependency.h" #include "qmt/model/mdiagram.h" #include "qmt/model/minheritance.h" @@ -81,12 +83,14 @@ public: void visitMObject(const MObject *object) override { Q_UNUSED(object); + // TODO enhance with handling MConnection m_accepted = dynamic_cast(m_relation) != 0; } void visitMClass(const MClass *klass) override { Q_UNUSED(klass); + // TODO enhance with handling MConnection m_accepted = dynamic_cast(m_relation) != 0 || dynamic_cast(m_relation) != 0 || dynamic_cast(m_relation) != 0; @@ -257,6 +261,44 @@ void DiagramSceneController::createAssociation(DClass *endAClass, DClass *endBCl emit newElementCreated(relation, diagram); } +void DiagramSceneController::createConnection(const QString &customRelationId, + DObject *endAObject, DObject *endBObject, + const QList &intermediatePoints, MDiagram *diagram, + std::function custom) +{ + m_diagramController->undoController()->beginMergeSequence(tr("Create Connection")); + + MObject *endAModelObject = m_modelController->findObject(endAObject->modelUid()); + QMT_CHECK(endAModelObject); + MObject *endBModelObject = m_modelController->findObject(endBObject->modelUid()); + QMT_CHECK(endBModelObject); + + // TODO allow self assignment with just one intermediate point and a nice round arrow + if (endAModelObject == endBModelObject && intermediatePoints.count() < 2) + return; + + auto modelConnection = new MConnection(); + modelConnection->setCustomRelationId(customRelationId); + modelConnection->setEndAUid(endAModelObject->uid()); + MConnectionEnd endA = modelConnection->endA(); + endA.setNavigable(true); + modelConnection->setEndA(endA); + modelConnection->setEndBUid(endBModelObject->uid()); + m_modelController->addRelation(endAModelObject, modelConnection); + + DRelation *relation = addRelation(modelConnection, intermediatePoints, diagram); + DConnection *diagramConnection = dynamic_cast(relation); + QMT_CHECK(diagramConnection); + + if (custom) + custom(modelConnection, diagramConnection); + + m_diagramController->undoController()->endMergeSequence(); + + if (relation) + emit newElementCreated(relation, diagram); +} + bool DiagramSceneController::relocateRelationEndA(DRelation *relation, DObject *targetObject) { return relocateRelationEnd(relation, targetObject, &MRelation::endAUid, &MRelation::setEndAUid); diff --git a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h index 855df4093e..a30e9926a7 100644 --- a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h +++ b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h @@ -44,11 +44,13 @@ class MPackage; class MDiagram; class MRelation; class MAssociation; +class MConnection; class DElement; class DObject; class DClass; class DRelation; class DAssociation; +class DConnection; class DSelection; class IElementTasks; class ISceneInspector; @@ -86,6 +88,9 @@ public: void createAssociation(DClass *endAClass, DClass *endBClass, const QList &intermediatePoints, MDiagram *diagram, std::function custom = 0); + void createConnection(const QString &customRelationId, DObject *endAObject, DObject *endBObject, + const QList &intermediatePoints, MDiagram *diagram, + std::function custom = 0); bool relocateRelationEndA(DRelation *relation, DObject *targetObject); bool relocateRelationEndB(DRelation *relation, DObject *targetObject); diff --git a/src/plugins/modeleditor/openelementvisitor.cpp b/src/plugins/modeleditor/openelementvisitor.cpp index 05cca71e39..312a67376a 100644 --- a/src/plugins/modeleditor/openelementvisitor.cpp +++ b/src/plugins/modeleditor/openelementvisitor.cpp @@ -37,6 +37,7 @@ #include "qmt/diagram/ddependency.h" #include "qmt/diagram/dinheritance.h" #include "qmt/diagram/dassociation.h" +#include "qmt/diagram/dconnection.h" #include "qmt/model/melement.h" #include "qmt/model/mpackage.h" @@ -121,6 +122,11 @@ void OpenDiagramElementVisitor::visitDAssociation(const qmt::DAssociation *assoc visitDRelation(association); } +void OpenDiagramElementVisitor::visitDConnection(const qmt::DConnection *connection) +{ + visitDRelation(connection); +} + void OpenDiagramElementVisitor::visitDAnnotation(const qmt::DAnnotation *annotation) { Q_UNUSED(annotation); @@ -199,5 +205,10 @@ void OpenModelElementVisitor::visitMAssociation(const qmt::MAssociation *associa Q_UNUSED(association); } +void OpenModelElementVisitor::visitMConnection(const qmt::MConnection *connection) +{ + Q_UNUSED(connection); +} + } // namespace Internal } // namespace ModelEditor diff --git a/src/plugins/modeleditor/openelementvisitor.h b/src/plugins/modeleditor/openelementvisitor.h index 48e0408076..4848afa2e3 100644 --- a/src/plugins/modeleditor/openelementvisitor.h +++ b/src/plugins/modeleditor/openelementvisitor.h @@ -53,6 +53,7 @@ public: void visitDInheritance(const qmt::DInheritance *inheritance); void visitDDependency(const qmt::DDependency *dependency); void visitDAssociation(const qmt::DAssociation *association); + void visitDConnection(const qmt::DConnection *connection); void visitDAnnotation(const qmt::DAnnotation *annotation); void visitDBoundary(const qmt::DBoundary *boundary); @@ -79,6 +80,7 @@ public: void visitMDependency(const qmt::MDependency *dependency) override; void visitMInheritance(const qmt::MInheritance *inheritance) override; void visitMAssociation(const qmt::MAssociation *association) override; + void visitMConnection(const qmt::MConnection *connection) override; private: ElementTasks *m_elementTasks = 0; -- GitLab