diff options
author | Jochen Becher <jochen_becher@gmx.de> | 2024-04-16 13:17:14 +0200 |
---|---|---|
committer | Jochen Becher <jochen_becher@gmx.de> | 2024-04-16 12:13:03 +0000 |
commit | a296157f58a5fa31861daa359b2ef8998d06c8a6 (patch) | |
tree | eea64fb53d725e960226b7ea8a868020eed3c768 /src/libs/modelinglib | |
parent | 5b9f2d5b3efcc118c6c313d7f65ce69d036d682b (diff) |
ModelEditor: Add dialog for adding related elements
Change-Id: Iae832885278472bb42a588fc97967ae5ffad6b71
Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
Diffstat (limited to 'src/libs/modelinglib')
8 files changed, 678 insertions, 10 deletions
diff --git a/src/libs/modelinglib/CMakeLists.txt b/src/libs/modelinglib/CMakeLists.txt index dcc810eb21..afea6c1699 100644 --- a/src/libs/modelinglib/CMakeLists.txt +++ b/src/libs/modelinglib/CMakeLists.txt @@ -131,6 +131,8 @@ add_qtc_library(Modeling qmt/model_ui/stereotypescontroller.cpp qmt/model_ui/stereotypescontroller.h qmt/model_ui/treemodel.cpp qmt/model_ui/treemodel.h qmt/model_ui/treemodelmanager.cpp qmt/model_ui/treemodelmanager.h + qmt/model_widgets_ui/addrelatedelementsdialog.h qmt/model_widgets_ui/addrelatedelementsdialog.cpp + qmt/model_widgets_ui/addrelatedelementsdialog.ui qmt/model_widgets_ui/classmembersedit.cpp qmt/model_widgets_ui/classmembersedit.h qmt/model_widgets_ui/modeltreeview.cpp qmt/model_widgets_ui/modeltreeview.h qmt/model_widgets_ui/palettebox.cpp qmt/model_widgets_ui/palettebox.h diff --git a/src/libs/modelinglib/modelinglib.qbs b/src/libs/modelinglib/modelinglib.qbs index 409928d3cb..d4edfadf09 100644 --- a/src/libs/modelinglib/modelinglib.qbs +++ b/src/libs/modelinglib/modelinglib.qbs @@ -247,6 +247,9 @@ QtcLibrary { "model_ui/treemodel.h", "model_ui/treemodelmanager.cpp", "model_ui/treemodelmanager.h", + "model_widgets_ui/addrelatedelementsdialog.h", + "model_widgets_ui/addrelatedelementsdialog.cpp", + "model_widgets_ui/addrelatedelementsdialog.ui", "model_widgets_ui/classmembersedit.cpp", "model_widgets_ui/classmembersedit.h", "model_widgets_ui/modeltreeview.cpp", diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp index 5d747a6391..60009e5f50 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp +++ b/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp @@ -1092,7 +1092,6 @@ void ObjectItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) layoutMenu.addAction(new ContextMenuAction(Tr::tr("Equal Vertical Space"), "sameVBorderDistance", &alignMenu)); layoutMenu.setEnabled(m_diagramSceneModel->hasMultiObjectsSelection()); menu.addMenu(&layoutMenu); - menu.addAction(new ContextMenuAction(Tr::tr("Add Related Elements"), "addRelatedElements", &menu)); QAction *selectedAction = menu.exec(event->screenPos()); if (selectedAction) { @@ -1145,11 +1144,6 @@ void ObjectItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) align(IAlignable::AlignHeight, "height"); } else if (action->id() == "sameSize") { align(IAlignable::AlignSize, "size"); - } else if (action->id() == "addRelatedElements") { - DSelection selection = m_diagramSceneModel->selectedElements(); - if (selection.isEmpty()) - selection.append(m_object->uid(), m_diagramSceneModel->diagram()->uid()); - m_diagramSceneModel->diagramSceneController()->addRelatedElements(selection, m_diagramSceneModel->diagram()); } } } diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.cpp b/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.cpp new file mode 100644 index 0000000000..35bfeda6c7 --- /dev/null +++ b/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.cpp @@ -0,0 +1,378 @@ +// Copyright (C) 2018 Jochen Becher +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "addrelatedelementsdialog.h" +#include "ui_addrelatedelementsdialog.h" + +#include <qmt/tasks/diagramscenecontroller.h> +#include <qmt/diagram_controller/dselection.h> +#include <qmt/model/mdiagram.h> +#include <qmt/model/mrelation.h> +#include <qmt/model/mdependency.h> +#include <qmt/model/minheritance.h> +#include <qmt/model/massociation.h> +#include <qmt/model/mconnection.h> +#include <qmt/model_controller/modelcontroller.h> +#include <qmt/model_controller/mvoidvisitor.h> + +#include <QStringListModel> + + +namespace qmt { + +namespace { + +enum class RelationType { + Any, + Dependency, + Association, + Inheritance, + Connection +}; + +enum class RelationDirection { + Any, + Outgoing, + Incoming, + Bidirectional +}; + +enum class ElementType { + Any, + Package, + Component, + Class, + Diagram, + Item, +}; + +class Filter : public qmt::MVoidConstVisitor { +public: + + void setRelationType(RelationType newRelationType) + { + m_relationType = newRelationType; + } + + void setRelationTypeId(const QString &newRelationTypeId) + { + m_relationTypeId = newRelationTypeId; + } + + void setRelationDirection(RelationDirection newRelationDirection) + { + m_relationDirection = newRelationDirection; + } + + void setRelationStereotypes(const QStringList &newRelationStereotypes) + { + m_relationStereotypes = newRelationStereotypes; + } + + void setElementType(ElementType newElementType) + { + m_elementType = newElementType; + } + + void setElementStereotypes(const QStringList &newElementStereotypes) + { + m_elementStereotypes = newElementStereotypes; + } + + void setObject(const qmt::DObject *dobject, const qmt::MObject *mobject) + { + m_dobject = dobject; + m_mobject = mobject; + } + + void setRelation(const qmt::MRelation *relation) + { + m_relation = relation; + } + + bool keep() const { return m_keep; } + + void reset() + { + m_dobject = nullptr; + m_mobject = nullptr; + m_relation = nullptr; + m_keep = true; + } + + // MConstVisitor interface + void visitMObject(const qmt::MObject *object) override + { + if (!m_elementStereotypes.isEmpty()) { + const QStringList stereotypes = object->stereotypes(); + bool containsElementStereotype = std::any_of( + stereotypes.constBegin(), stereotypes.constEnd(), + [&](const QString &s) { return m_elementStereotypes.contains(s); }); + if (!containsElementStereotype) { + m_keep = false; + return; + } + } + } + + void visitMPackage(const qmt::MPackage *package) override + { + if (m_elementType == ElementType::Any || m_elementType == ElementType::Package) + qmt::MVoidConstVisitor::visitMPackage(package); + else + m_keep = false; + } + + void visitMClass(const qmt::MClass *klass) override + { + if (m_elementType == ElementType::Any || m_elementType == ElementType::Class) + qmt::MVoidConstVisitor::visitMClass(klass); + else + m_keep = false; + } + + void visitMComponent(const qmt::MComponent *component) override + { + if (m_elementType == ElementType::Any || m_elementType == ElementType::Component) + qmt::MVoidConstVisitor::visitMComponent(component); + else + m_keep = false; + } + + void visitMDiagram(const qmt::MDiagram *diagram) override + { + if (m_elementType == ElementType::Any || m_elementType == ElementType::Diagram) + qmt::MVoidConstVisitor::visitMDiagram(diagram); + else + m_keep = false; + } + + void visitMItem(const qmt::MItem *item) override + { + if (m_elementType == ElementType::Any || m_elementType == ElementType::Item) + qmt::MVoidConstVisitor::visitMItem(item); + else + m_keep = false; + } + + void visitMRelation(const qmt::MRelation *relation) override + { + if (!m_relationStereotypes.isEmpty()) { + const QStringList relationStereotypes = relation->stereotypes(); + bool containsRelationStereotype = std::any_of( + relationStereotypes.constBegin(), relationStereotypes.constEnd(), + [&](const QString &s) { return m_relationStereotypes.contains(s); }); + if (!containsRelationStereotype) { + m_keep = false; + return; + } + } + } + + void visitMDependency(const qmt::MDependency *dependency) override + { + if (m_relationDirection != RelationDirection::Any) { + bool keep = false; + if (m_relationDirection == RelationDirection::Outgoing) { + if (dependency->direction() == qmt::MDependency::AToB && dependency->endAUid() == m_mobject->uid()) + keep = true; + else if (dependency->direction() == qmt::MDependency::BToA && dependency->endBUid() == m_mobject->uid()) + keep = true; + } else if (m_relationDirection == RelationDirection::Incoming) { + if (dependency->direction() == qmt::MDependency::AToB && dependency->endBUid() == m_mobject->uid()) + keep = true; + else if (dependency->direction() == qmt::MDependency::BToA && dependency->endAUid() == m_mobject->uid()) + keep = true; + } else if (m_relationDirection == RelationDirection::Bidirectional) { + if (dependency->direction() == qmt::MDependency::Bidirectional) + keep = true; + } + m_keep = keep; + if (!keep) + return; + } + if (m_relationType == RelationType::Any || m_relationType == RelationType::Dependency) + qmt::MVoidConstVisitor::visitMDependency(dependency); + else + m_keep = false; + } + + bool testDirection(const qmt::MRelation *relation) + { + if (m_relationDirection != RelationDirection::Any) { + bool keep = false; + if (m_relationDirection == RelationDirection::Outgoing) { + if (relation->endAUid() == m_mobject->uid()) + keep = true; + } else if (m_relationDirection == RelationDirection::Incoming) { + if (relation->endBUid() == m_mobject->uid()) + keep = true; + } + m_keep = keep; + if (!keep) + return false; + } + return true; + } + + void visitMInheritance(const qmt::MInheritance *inheritance) override + { + if (!testDirection(inheritance)) + return; + if (m_relationType == RelationType::Any || m_relationType == RelationType::Inheritance) + qmt::MVoidConstVisitor::visitMInheritance(inheritance); + else + m_keep = false; + } + + void visitMAssociation(const qmt::MAssociation *association) override + { + if (!testDirection(association)) + return; + if (m_relationType == RelationType::Any || m_relationType == RelationType::Association) + qmt::MVoidConstVisitor::visitMAssociation(association); + else + m_keep = false; + } + + void visitMConnection(const qmt::MConnection *connection) override + { + if (!testDirection(connection)) + return; + if (m_relationType == RelationType::Any || m_relationType == RelationType::Connection) + qmt::MVoidConstVisitor::visitMConnection(connection); + else + m_keep = false; + } + +private: + RelationType m_relationType = RelationType::Any; + QString m_relationTypeId; + RelationDirection m_relationDirection = RelationDirection::Any; + QStringList m_relationStereotypes; + ElementType m_elementType = ElementType::Any; + QStringList m_elementStereotypes; + const qmt::DObject *m_dobject = nullptr; + const qmt::MObject *m_mobject = nullptr; + const qmt::MRelation *m_relation = nullptr; + bool m_keep = true; +}; +} // namespace + +class AddRelatedElementsDialog::Private { +public: + qmt::DiagramSceneController *m_diagramSceneController = nullptr; + qmt::DSelection m_selection; + qmt::Uid m_diagramUid; + QStringListModel m_relationTypeModel; + QStringListModel m_relationDirectionModel; + QStringListModel m_relationStereotypesModel; + QStringListModel m_elementTypeModel; + QStringListModel m_elementStereotypesModel; + Filter m_filter; +}; + +AddRelatedElementsDialog::AddRelatedElementsDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::AddRelatedElementsDialog), + d(new Private) +{ + ui->setupUi(this); + connect(ui->RelationTypeCombobox, &QComboBox::currentIndexChanged, this, &AddRelatedElementsDialog::updateNumberOfElements); + connect(ui->DirectionCombobox, &QComboBox::currentIndexChanged, this, &AddRelatedElementsDialog::updateNumberOfElements); + connect(ui->StereotypesCombobox, &QComboBox::currentTextChanged, this, &AddRelatedElementsDialog::updateNumberOfElements); + connect(ui->ElementTypeComboBox, &QComboBox::currentIndexChanged, this, &AddRelatedElementsDialog::updateNumberOfElements); + connect(ui->ElementStereotypesCombobox, &QComboBox::currentTextChanged, this, &AddRelatedElementsDialog::updateNumberOfElements); + connect(this, &QDialog::accepted, this, &AddRelatedElementsDialog::onAccepted); +} + +AddRelatedElementsDialog::~AddRelatedElementsDialog() +{ + delete d; + delete ui; +} + +void AddRelatedElementsDialog::setDiagramSceneController(qmt::DiagramSceneController *diagramSceneController) +{ + d->m_diagramSceneController = diagramSceneController; +} + +void AddRelatedElementsDialog::setElements(const qmt::DSelection &selection, qmt::MDiagram *diagram) +{ + d->m_selection = selection; + d->m_diagramUid = diagram->uid(); + QStringList relationTypes = {"Any", "Dependency", "Association", "Inheritance"}; + d->m_relationTypeModel.setStringList(relationTypes); + ui->RelationTypeCombobox->setModel(&d->m_relationTypeModel); + QStringList relationDirections = {"Any", "Outgoing (->)", "Incoming (<-)", "Bidirectional (<->)"}; + d->m_relationDirectionModel.setStringList(relationDirections); + ui->DirectionCombobox->setModel(&d->m_relationDirectionModel); + QStringList relationStereotypes = { }; + d->m_relationStereotypesModel.setStringList(relationStereotypes); + ui->StereotypesCombobox->setModel(&d->m_relationStereotypesModel); + QStringList elementTypes = {"Any", "Package", "Component", "Class", "Diagram", "Item"}; + d->m_elementTypeModel.setStringList(elementTypes); + ui->ElementTypeComboBox->setModel(&d->m_elementTypeModel); + QStringList elementStereotypes = { }; + d->m_elementStereotypesModel.setStringList(elementStereotypes); + ui->ElementStereotypesCombobox->setModel(&d->m_elementStereotypesModel); + updateNumberOfElements(); +} + +void AddRelatedElementsDialog::onAccepted() +{ + qmt::MDiagram *diagram = d->m_diagramSceneController->modelController()->findElement<qmt::MDiagram>(d->m_diagramUid); + if (diagram) { + updateFilter(); + d->m_diagramSceneController->addRelatedElements( + d->m_selection, diagram, + [this](qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation) -> bool + { + return this->filter(dobject, mobject, relation); + }); + } +} + +void AddRelatedElementsDialog::updateFilter() +{ + d->m_filter.setRelationType((RelationType) ui->RelationTypeCombobox->currentIndex()); + d->m_filter.setRelationDirection((RelationDirection) ui->DirectionCombobox->currentIndex()); + d->m_filter.setRelationStereotypes(ui->StereotypesCombobox->currentText().split(',', Qt::SkipEmptyParts)); + d->m_filter.setElementType((ElementType) ui->ElementTypeComboBox->currentIndex()); + d->m_filter.setElementStereotypes(ui->ElementStereotypesCombobox->currentText().split(',', Qt::SkipEmptyParts)); +} + +bool AddRelatedElementsDialog::filter(qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation) +{ + d->m_filter.reset(); + d->m_filter.setObject(dobject, mobject); + d->m_filter.setRelation(relation); + relation->accept(&d->m_filter); + if (!d->m_filter.keep()) + return false; + qmt::MObject *targetObject = nullptr; + if (relation->endAUid() != mobject->uid()) + targetObject = d->m_diagramSceneController->modelController()->findObject(relation->endAUid()); + else if (relation->endBUid() != mobject->uid()) + targetObject = d->m_diagramSceneController->modelController()->findObject(relation->endBUid()); + if (!targetObject) + return false; + targetObject->accept(&d->m_filter); + return d->m_filter.keep(); +} + +void AddRelatedElementsDialog::updateNumberOfElements() +{ + qmt::MDiagram *diagram = d->m_diagramSceneController->modelController()->findElement<qmt::MDiagram>(d->m_diagramUid); + if (diagram) { + updateFilter(); + ui->NumberOfMatchingElementsValue->setText(QString::number(d->m_diagramSceneController->countRelatedElements( + d->m_selection, diagram, + [this](qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation) -> bool + { + return this->filter(dobject, mobject, relation); + }))); + } +} + +} // namespace qmt diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.h b/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.h new file mode 100644 index 0000000000..1c7edb1d57 --- /dev/null +++ b/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.h @@ -0,0 +1,48 @@ +// Copyright (C) 2018 Jochen Becher +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "qmt/infrastructure/qmt_global.h" + +#include <QDialog> + +namespace qmt { + +class DSelection; +class DObject; +class MObject; +class MDiagram; +class MRelation; +class DiagramSceneController; +} + +namespace Ui { +class AddRelatedElementsDialog; +} + +namespace qmt { + +class QMT_EXPORT AddRelatedElementsDialog : public QDialog +{ + Q_OBJECT + class Private; + +public: + explicit AddRelatedElementsDialog(QWidget *parent = nullptr); + ~AddRelatedElementsDialog(); + + void setDiagramSceneController(qmt::DiagramSceneController *diagramSceneController); + void setElements(const qmt::DSelection &selection, qmt::MDiagram *diagram); + +private: + void onAccepted(); + void updateFilter(); + bool filter(qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation); + void updateNumberOfElements(); + + Ui::AddRelatedElementsDialog *ui = nullptr; + Private *d = nullptr; +}; + +} // namespace qmt diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.ui b/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.ui new file mode 100644 index 0000000000..0dc2cf04ca --- /dev/null +++ b/src/libs/modelinglib/qmt/model_widgets_ui/addrelatedelementsdialog.ui @@ -0,0 +1,190 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>AddRelatedElementsDialog</class> + <widget class="QDialog" name="AddRelatedElementsDialog"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>500</width> + <height>0</height> + </size> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QGroupBox" name="relationBox"> + <property name="title"> + <string>Relation Attributes</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="RelationTypeLabel"> + <property name="text"> + <string>Type</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="RelationTypeCombobox"/> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="DirectionLabel"> + <property name="text"> + <string>Direction</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="DirectionCombobox"/> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="StereotypesLabel"> + <property name="text"> + <string>Stereotypes</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QComboBox" name="StereotypesCombobox"> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="elementBox"> + <property name="title"> + <string>Other Element Attributes</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QFormLayout" name="formLayout_2"> + <item row="1" column="0"> + <widget class="QLabel" name="ElementTypeLabel"> + <property name="text"> + <string>Type</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="ElementStereotypesLabel"> + <property name="text"> + <string>Stereotypes</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QComboBox" name="ElementStereotypesCombobox"> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="ElementTypeComboBox"> + <property name="editable"> + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <layout class="QFormLayout" name="formLayout_3"> + <item row="0" column="0"> + <widget class="QLabel" name="NumberOfMatchingElementsLabel"> + <property name="text"> + <string>Number of matching elements: </string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="NumberOfMatchingElementsValue"> + <property name="text"> + <string>0</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::MinimumExpanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>AddRelatedElementsDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>AddRelatedElementsDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp index 00aacf9c82..51f414f66e 100644 --- a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp +++ b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp @@ -421,7 +421,44 @@ void DiagramSceneController::dropNewModelElement(MObject *modelObject, MPackage emit newElementCreated(element, diagram); } -void DiagramSceneController::addRelatedElements(const DSelection &selection, MDiagram *diagram) +int DiagramSceneController::countRelatedElements(const DSelection &selection, MDiagram *diagram, std::function<bool (qmt::DObject *, qmt::MObject *, qmt::MRelation *)> filter) +{ + int counter = 0; + const QList<DSelection::Index> indices = selection.indices(); + for (const DSelection::Index &index : indices) { + DElement *delement = m_diagramController->findElement(index.elementKey(), diagram); + QMT_ASSERT(delement, return 0); + DObject *dobject = dynamic_cast<DObject *>(delement); + if (dobject && dobject->modelUid().isValid()) { + MObject *mobject = m_modelController->findElement<MObject>(delement->modelUid()); + if (mobject) { + const QList<MRelation *> relations = m_modelController->findRelationsOfObject(mobject); + QList<MRelation *> filteredRelations; + const QList<MRelation *> *relationsList = nullptr; + if (filter) { + for (MRelation *relation : relations) { + if (filter(dobject, mobject, relation)) + filteredRelations.append(relation); + } + relationsList = &filteredRelations; + } else { + relationsList = &relations; + } + for (MRelation *relation : *relationsList) { + if (relation->endAUid() != mobject->uid()) + ++counter; + else if (relation->endBUid() != mobject->uid()) + ++counter; + } + } + } + } + return counter; +} + +void DiagramSceneController::addRelatedElements( + const DSelection &selection, MDiagram *diagram, + std::function<bool (qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation)> filter) { m_diagramController->undoController()->beginMergeSequence(Tr::tr("Add Related Element")); const QList<DSelection::Index> indices = selection.indices(); @@ -435,8 +472,19 @@ void DiagramSceneController::addRelatedElements(const DSelection &selection, MDi qreal dAngle = 360.0 / 11.5; qreal dRadius = 100.0; const QList<MRelation *> relations = m_modelController->findRelationsOfObject(mobject); + QList<MRelation *> filteredRelations; + const QList<MRelation *> *relationsList = nullptr; + if (filter) { + for (MRelation *relation : relations) { + if (filter(dobject, mobject, relation)) + filteredRelations.append(relation); + } + relationsList = &filteredRelations; + } else { + relationsList = &relations; + } int count = 0; - for (MRelation *relation : relations) { + for (MRelation *relation : *relationsList) { if (relation->endAUid() != mobject->uid() || relation->endBUid() != mobject->uid()) ++count; } @@ -446,7 +494,7 @@ void DiagramSceneController::addRelatedElements(const DSelection &selection, MDi } qreal radius = 200.0; qreal angle = 0.0; - for (MRelation *relation : relations) { + for (MRelation *relation : *relationsList) { QPointF pos(dobject->pos()); pos += QPointF(radius * sin(angle / 180 * M_PI), -radius * cos(angle / 180 * M_PI)); bool added = false; diff --git a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h index a062fa10c4..14e704a192 100644 --- a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h +++ b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h @@ -86,7 +86,12 @@ public: DElement *topMostElementAtPos, const QPointF &pos, MDiagram *diagram, const QPoint &viewPos, const QSize &viewSize); void dropNewModelElement(MObject *modelObject, MPackage *parentPackage, const QPointF &pos, MDiagram *diagram); - void addRelatedElements(const DSelection &selection, MDiagram *diagram); + int countRelatedElements( + const DSelection &selection, MDiagram *diagram, + std::function<bool (qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation)> filter); + void addRelatedElements( + const DSelection &selection, MDiagram *diagram, + std::function<bool (qmt::DObject *dobject, qmt::MObject *mobject, qmt::MRelation *relation)> filter); MPackage *findSuitableParentPackage(DElement *topmostDiagramElement, MDiagram *diagram); MDiagram *findDiagramBySearchId(MPackage *package, const QString &diagramName); |