diff --git a/src/plugins/modeleditor/actionhandler.cpp b/src/plugins/modeleditor/actionhandler.cpp index a2dabcfdcd8..8f0d31a9833 100644 --- a/src/plugins/modeleditor/actionhandler.cpp +++ b/src/plugins/modeleditor/actionhandler.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,7 @@ public: QAction *deleteAction = 0; QAction *selectAllAction = 0; QAction *openParentDiagramAction = 0; + QAction *synchronizeBrowserAction = 0; QAction *exportDiagramAction = 0; QAction *zoomInAction = 0; QAction *zoomOutAction = 0; @@ -116,6 +118,11 @@ QAction *ActionHandler::openParentDiagramAction() const return d->openParentDiagramAction; } +QAction *ActionHandler::synchronizeBrowserAction() const +{ + return d->synchronizeBrowserAction; +} + QAction *ActionHandler::exportDiagramAction() const { return d->exportDiagramAction; @@ -196,6 +203,13 @@ void ActionHandler::createActions() registerCommand(Constants::ACTION_ADD_COMPONENT, nullptr, Core::Context()); registerCommand(Constants::ACTION_ADD_CLASS, nullptr, Core::Context()); registerCommand(Constants::ACTION_ADD_CANVAS_DIAGRAM, nullptr, Core::Context()); + d->synchronizeBrowserAction = registerCommand( + Constants::ACTION_SYNC_BROWSER, nullptr, Core::Context(), true, + tr("Synchronize Browser and Diagram
Press&Hold for options"))->action(); + static const Utils::Icon + LINK_ICON({{ QStringLiteral(":/core/images/linkicon.png"), Utils::Theme::IconsBaseColor }}); + d->synchronizeBrowserAction->setIcon(LINK_ICON.icon()); + d->synchronizeBrowserAction->setCheckable(true); auto editPropertiesAction = new QAction(tr("Edit Element Properties"), Core::ICore::mainWindow()); Core::Command *editPropertiesCommand = Core::ActionManager::registerAction( diff --git a/src/plugins/modeleditor/actionhandler.h b/src/plugins/modeleditor/actionhandler.h index 958d53997a5..dff6a4ae29c 100644 --- a/src/plugins/modeleditor/actionhandler.h +++ b/src/plugins/modeleditor/actionhandler.h @@ -63,6 +63,7 @@ public: QAction *deleteAction() const; QAction *selectAllAction() const; QAction *openParentDiagramAction() const; + QAction *synchronizeBrowserAction() const; QAction *exportDiagramAction() const; QAction *zoomInAction() const; QAction *zoomOutAction() const; diff --git a/src/plugins/modeleditor/modeleditor.cpp b/src/plugins/modeleditor/modeleditor.cpp index f1dce77a729..f0fd3de9e8f 100644 --- a/src/plugins/modeleditor/modeleditor.cpp +++ b/src/plugins/modeleditor/modeleditor.cpp @@ -94,6 +94,7 @@ #include #include #include +#include #include @@ -127,6 +128,9 @@ public: QComboBox *diagramSelector = 0; SelectedArea selectedArea = SelectedArea::Nothing; QString lastExportDirPath; + QAction *syncBrowserWithDiagramAction = 0; + QAction *syncDiagramWithBrowserAction = 0; + QAction *syncEachOtherAction = 0; }; ModelEditor::ModelEditor(UiController *uiController, ActionHandler *actionHandler, QWidget *parent) @@ -168,9 +172,21 @@ bool ModelEditor::restoreState(const QByteArray &state) QDataStream stream(state); int version = 0; stream >> version; - if (version == 1) { + if (version >= 1) { qmt::Uid uid; stream >> uid; + if (version >= 2) { + bool sync = false; + bool syncBrowserWithDiagram = false; + bool syncDiagramWithBrowser = false; + bool syncEachOther = false; + stream >> sync >> syncBrowserWithDiagram >> syncDiagramWithBrowser >> syncEachOther; + d->actionHandler->synchronizeBrowserAction()->setChecked(sync); + d->syncBrowserWithDiagramAction->setChecked( + syncBrowserWithDiagram || (!syncDiagramWithBrowser && !syncEachOther)); + d->syncDiagramWithBrowserAction->setChecked(syncDiagramWithBrowser); + d->syncEachOtherAction->setChecked(syncEachOther); + } if (uid.isValid()) { qmt::MDiagram *diagram = d->document->documentController()->modelController()->findObject(uid); if (diagram) { @@ -320,6 +336,23 @@ void ModelEditor::init(QWidget *parent) QIcon(QStringLiteral(":/modelinglib/48x48/canvas-diagram.png")), tr("Add Canvas Diagram"), d->toolbar)); toolbarLayout->addSpacing(20); + + auto syncToggleButton = new Core::CommandButton(Constants::ACTION_SYNC_BROWSER, d->toolbar); + syncToggleButton->setDefaultAction(d->actionHandler->synchronizeBrowserAction()); + QMenu *syncMenu = new QMenu(syncToggleButton); + QActionGroup *syncGroup = new QActionGroup(syncMenu); + d->syncBrowserWithDiagramAction = syncMenu->addAction(QStringLiteral("Synchronize Browser with Diagram")); + d->syncBrowserWithDiagramAction->setCheckable(true); + d->syncBrowserWithDiagramAction->setActionGroup(syncGroup); + d->syncDiagramWithBrowserAction = syncMenu->addAction(QStringLiteral("Synchronize Diagram with Browser")); + d->syncDiagramWithBrowserAction->setCheckable(true); + d->syncDiagramWithBrowserAction->setActionGroup(syncGroup); + d->syncEachOtherAction = syncMenu->addAction(QStringLiteral("Synchronize Each Other")); + d->syncEachOtherAction->setCheckable(true); + d->syncEachOtherAction->setActionGroup(syncGroup); + syncToggleButton->setMenu(syncMenu); + d->syncBrowserWithDiagramAction->setChecked(true); + toolbarLayout->addWidget(syncToggleButton); } void ModelEditor::initDocument() @@ -745,13 +778,17 @@ void ModelEditor::expandModelTreeToDepth(int depth) d->modelTreeView->expandToDepth(depth); } -QWidget *ModelEditor::createToolbarCommandButton(const Core::Id &id, const std::function &slot, - const QIcon &icon, const QString &toolTipBase, - QWidget *parent) +QToolButton *ModelEditor::createToolbarCommandButton(const Core::Id &id, const std::function &slot, + const QIcon &icon, const QString &toolTipBase, + QWidget *parent) { auto button = new Core::CommandButton(id, parent); - button->setIcon(icon); - button->setToolTipBase(toolTipBase); + auto action = new QAction(button); + action->setIcon(icon); + action->setToolTip(toolTipBase); + button->setDefaultAction(action); + //button->setIcon(icon); + //button->setToolTipBase(toolTipBase); connect(button, &Core::CommandButton::clicked, this, slot); return button; } @@ -854,6 +891,7 @@ void ModelEditor::onTreeViewSelectionChanged(const QItemSelection &selected, Q_UNUSED(selected); Q_UNUSED(deselected); + synchronizeDiagramWithBrowser(); updateSelectedArea(SelectedArea::TreeView); } @@ -911,8 +949,10 @@ void ModelEditor::onNewElementCreated(qmt::DElement *element, qmt::MDiagram *dia void ModelEditor::onDiagramSelectionChanged(const qmt::MDiagram *diagram) { - if (diagram == currentDiagram()) + if (diagram == currentDiagram()) { + synchronizeBrowserWithDiagram(diagram); updateSelectedArea(SelectedArea::Diagram); + } } void ModelEditor::onDiagramModified(const qmt::MDiagram *diagram) @@ -1258,11 +1298,15 @@ QByteArray ModelEditor::saveState(const qmt::MDiagram *diagram) const { QByteArray state; QDataStream stream(&state, QIODevice::WriteOnly); - stream << 1; // version number + stream << 2; // version number if (diagram) stream << diagram->uid(); else stream << qmt::Uid::invalidUid(); + stream << d->actionHandler->synchronizeBrowserAction()->isChecked() + << d->syncBrowserWithDiagramAction->isChecked() + << d->syncDiagramWithBrowserAction->isChecked() + << d->syncEachOtherAction->isChecked(); return state; } @@ -1287,5 +1331,79 @@ void ModelEditor::onEditSelectedElement() } } +bool ModelEditor::isSyncBrowserWithDiagram() const +{ + return d->actionHandler->synchronizeBrowserAction()->isChecked() + && (d->syncBrowserWithDiagramAction->isChecked() || d->syncEachOtherAction->isChecked()); +} + +bool ModelEditor::isSyncDiagramWithBrowser() const +{ + return d->actionHandler->synchronizeBrowserAction()->isChecked() + && (d->syncDiagramWithBrowserAction->isChecked() || d->syncEachOtherAction->isChecked()); +} + +void ModelEditor::synchronizeDiagramWithBrowser() +{ + if (isSyncDiagramWithBrowser()) { + if (currentDiagram()) { + bool done = false; + qmt::DocumentController *documentController = d->document->documentController(); + QModelIndexList indexes = d->modelTreeView->selectedSourceModelIndexes(); + if (!indexes.isEmpty()) { + foreach (const QModelIndex &index, indexes) { + if (index.isValid()) { + qmt::MElement *modelElement = documentController->treeModel()->element(index); + if (modelElement) { + foreach (qmt::DElement *diagramElement, currentDiagram()->diagramElements()) { + if (diagramElement->modelUid() == modelElement->uid()) { + // disconnect temporarily avoiding double update of properties Ui + disconnect(documentController->diagramsManager(), &qmt::DiagramsManager::diagramSelectionChanged, + this, &ModelEditor::onDiagramSelectionChanged); + d->diagramView->diagramSceneModel()->selectElement(diagramElement); + connect(documentController->diagramsManager(), &qmt::DiagramsManager::diagramSelectionChanged, + this, &ModelEditor::onDiagramSelectionChanged, Qt::QueuedConnection); + done = true; + break; + } + } + if (done) + break; + } + } + } + } + } + } +} + +void ModelEditor::synchronizeBrowserWithDiagram(const qmt::MDiagram *diagram) +{ + if (isSyncBrowserWithDiagram()) { + qmt::DocumentController *documentController = d->document->documentController(); + qmt::DSelection selection = documentController->diagramsManager()->diagramSceneModel(diagram)->selectedElements(); + if (!selection.isEmpty()) { + foreach (qmt::DSelection::Index index, selection.indices()) { + qmt::DElement *diagramElement = documentController->diagramController()->findElement(index.elementKey(), diagram); + if (diagramElement) { + qmt::MElement *modelElement = documentController->modelController()->findElement(diagramElement->modelUid()); + if (modelElement) { + QModelIndex index = d->modelTreeViewServant->treeModel()->indexOf(modelElement); + if (index.isValid()) { + // disconnect temporarily avoiding double update of properties Ui + disconnect(d->modelTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, + this, &ModelEditor::onTreeViewSelectionChanged); + d->modelTreeView->selectFromSourceModelIndex(index); + connect(d->modelTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, + this, &ModelEditor::onTreeViewSelectionChanged, Qt::QueuedConnection); + break; + } + } + } + } + } + } +} + } // namespace Internal } // namespace ModelEditor diff --git a/src/plugins/modeleditor/modeleditor.h b/src/plugins/modeleditor/modeleditor.h index 53d4447324c..7c51751a90c 100644 --- a/src/plugins/modeleditor/modeleditor.h +++ b/src/plugins/modeleditor/modeleditor.h @@ -33,6 +33,7 @@ QT_BEGIN_NAMESPACE class QItemSelection; +class QToolButton; QT_END_NAMESPACE namespace qmt { @@ -101,7 +102,7 @@ private: void showProperties(qmt::MDiagram *diagram, const QList &diagramElements); void clearProperties(); void expandModelTreeToDepth(int depth); - QWidget *createToolbarCommandButton(const Core::Id &id, const std::function &slot, + QToolButton *createToolbarCommandButton(const Core::Id &id, const std::function &slot, const QIcon &icon, const QString &toolTipBase, QWidget *parent); bool updateButtonIconByTheme(QAbstractButton *button, const QString &name); @@ -148,8 +149,11 @@ private: void addToNavigationHistory(const qmt::MDiagram *diagram); QByteArray saveState(const qmt::MDiagram *diagram) const; -private slots: void onEditSelectedElement(); + bool isSyncBrowserWithDiagram() const; + bool isSyncDiagramWithBrowser() const; + void synchronizeDiagramWithBrowser(); + void synchronizeBrowserWithDiagram(const qmt::MDiagram *diagram); private: ModelEditorPrivate *d; diff --git a/src/plugins/modeleditor/modeleditor_constants.h b/src/plugins/modeleditor/modeleditor_constants.h index 9ebdf13529d..facd3ece881 100644 --- a/src/plugins/modeleditor/modeleditor_constants.h +++ b/src/plugins/modeleditor/modeleditor_constants.h @@ -43,6 +43,7 @@ const char ACTION_ADD_PACKAGE[] = "ModelEditor.Action.AddPackage"; const char ACTION_ADD_COMPONENT[] = "ModelEditor.Action.AddComponent"; const char ACTION_ADD_CLASS[] = "ModelEditor.Action.AddClass"; const char ACTION_ADD_CANVAS_DIAGRAM[] = "ModelEditor.Action.AddCanvasDiagram"; +const char ACTION_SYNC_BROWSER[] = "ModelEditor.Action.SynchronizeBrowser"; const char EXPLORER_GROUP_MODELING[] = "ModelEditor.ProjectFolder.Group.Modeling"; const char ACTION_EXPLORER_OPEN_DIAGRAM[] = "ModelEditor.Action.Explorer.OpenDiagram";