aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorJochen Becher <jochen_becher@gmx.de>2015-08-31 18:06:36 +0200
committerJochen Becher <jochen_becher@gmx.de>2015-09-16 12:13:36 +0000
commitd92142f14922ba26c6bd530c71db22f9561f9cd6 (patch)
tree300421733b88b3eb40ffbc7f3a3c0398a5a1459d /src/plugins
parent64e2ba87ef4cffc754d64d411a483316378080d5 (diff)
Add new ModelEditor plugin.
The plugin is based on the 'modelinglib' library. For features and screenshots see https://wiki.qt.io/ModelEditor Change-Id: I857be0652a852cc69a9729f64e67134fe630af00 Reviewed-by: Tobias Hunger <tobias.hunger@theqtcompany.com>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/modeleditor/ModelEditor.json.in20
-rw-r--r--src/plugins/modeleditor/abstracteditor.cpp942
-rw-r--r--src/plugins/modeleditor/abstracteditor.h144
-rw-r--r--src/plugins/modeleditor/actionhandler.cpp225
-rw-r--r--src/plugins/modeleditor/actionhandler.h98
-rw-r--r--src/plugins/modeleditor/classviewcontroller.cpp101
-rw-r--r--src/plugins/modeleditor/classviewcontroller.h59
-rw-r--r--src/plugins/modeleditor/componentviewcontroller.cpp439
-rw-r--r--src/plugins/modeleditor/componentviewcontroller.h73
-rw-r--r--src/plugins/modeleditor/diagramdocument.cpp210
-rw-r--r--src/plugins/modeleditor/diagramdocument.h76
-rw-r--r--src/plugins/modeleditor/diagrameditor.cpp89
-rw-r--r--src/plugins/modeleditor/diagrameditor.h62
-rw-r--r--src/plugins/modeleditor/diagrameditorfactory.cpp78
-rw-r--r--src/plugins/modeleditor/diagrameditorfactory.h62
-rw-r--r--src/plugins/modeleditor/diagramsviewmanager.cpp87
-rw-r--r--src/plugins/modeleditor/diagramsviewmanager.h80
-rw-r--r--src/plugins/modeleditor/documentinterface.h51
-rw-r--r--src/plugins/modeleditor/dragtool.cpp182
-rw-r--r--src/plugins/modeleditor/dragtool.h67
-rw-r--r--src/plugins/modeleditor/editordiagramview.cpp84
-rw-r--r--src/plugins/modeleditor/editordiagramview.h60
-rw-r--r--src/plugins/modeleditor/elementtasks.cpp355
-rw-r--r--src/plugins/modeleditor/elementtasks.h93
-rw-r--r--src/plugins/modeleditor/extdocumentcontroller.cpp89
-rw-r--r--src/plugins/modeleditor/extdocumentcontroller.h65
-rw-r--r--src/plugins/modeleditor/modeldocument.cpp192
-rw-r--r--src/plugins/modeleditor/modeldocument.h80
-rw-r--r--src/plugins/modeleditor/modeleditor.cpp84
-rw-r--r--src/plugins/modeleditor/modeleditor.h62
-rw-r--r--src/plugins/modeleditor/modeleditor.pro90
-rw-r--r--src/plugins/modeleditor/modeleditor.qbs75
-rw-r--r--src/plugins/modeleditor/modeleditor_constants.h73
-rw-r--r--src/plugins/modeleditor/modeleditor_dependencies.pri12
-rw-r--r--src/plugins/modeleditor/modeleditor_file_wizard.cpp128
-rw-r--r--src/plugins/modeleditor/modeleditor_file_wizard.h60
-rw-r--r--src/plugins/modeleditor/modeleditor_global.h42
-rw-r--r--src/plugins/modeleditor/modeleditor_plugin.cpp151
-rw-r--r--src/plugins/modeleditor/modeleditor_plugin.h67
-rw-r--r--src/plugins/modeleditor/modeleditorfactory.cpp79
-rw-r--r--src/plugins/modeleditor/modeleditorfactory.h62
-rw-r--r--src/plugins/modeleditor/modelindexer.cpp615
-rw-r--r--src/plugins/modeleditor/modelindexer.h95
-rw-r--r--src/plugins/modeleditor/modelsmanager.cpp465
-rw-r--r--src/plugins/modeleditor/modelsmanager.h95
-rw-r--r--src/plugins/modeleditor/openelementvisitor.cpp208
-rw-r--r--src/plugins/modeleditor/openelementvisitor.h96
-rw-r--r--src/plugins/modeleditor/pxnodecontroller.cpp389
-rw-r--r--src/plugins/modeleditor/pxnodecontroller.h78
-rw-r--r--src/plugins/modeleditor/pxnodeutilities.cpp246
-rw-r--r--src/plugins/modeleditor/pxnodeutilities.h72
-rw-r--r--src/plugins/modeleditor/resources/modeleditor.mimetypes.xml14
-rw-r--r--src/plugins/modeleditor/resources/modeleditor.qrc5
-rw-r--r--src/plugins/modeleditor/settingscontroller.cpp66
-rw-r--r--src/plugins/modeleditor/settingscontroller.h65
-rw-r--r--src/plugins/modeleditor/uicontroller.cpp116
-rw-r--r--src/plugins/modeleditor/uicontroller.h76
-rw-r--r--src/plugins/plugins.pro1
-rw-r--r--src/plugins/plugins.qbs1
59 files changed, 7851 insertions, 0 deletions
diff --git a/src/plugins/modeleditor/ModelEditor.json.in b/src/plugins/modeleditor/ModelEditor.json.in
new file mode 100644
index 00000000000..0bd9c9ca743
--- /dev/null
+++ b/src/plugins/modeleditor/ModelEditor.json.in
@@ -0,0 +1,20 @@
+{
+ \"Name\" : \"ModelEditor\",
+ \"Version\" : \"$$QTCREATOR_VERSION\",
+ \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\",
+ \"Vendor\" : \"Jochen Becher\",
+ \"Copyright\" : \"(C) 2014,2015 Jochen Becher\",
+ \"License\" : [ \"Commercial Usage\",
+ \"\",
+ \"Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt 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.\",
+ \"\",
+ \"GNU Lesser General Public License Usage\",
+ \"\",
+ \"Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 or version 3 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License requirements will be met: https://www.gnu.org/licenses/lgpl.html and http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.\"
+ ],
+ \"Category\" : \"Modeling\",
+ \"Description\" : \"Graphical modeling with structured diagrams.\",
+ \"Url\" : \"http://www.qt.io\",
+ \"Experimental\" : true,
+ $$dependencyList
+}
diff --git a/src/plugins/modeleditor/abstracteditor.cpp b/src/plugins/modeleditor/abstracteditor.cpp
new file mode 100644
index 00000000000..0b45535f0d8
--- /dev/null
+++ b/src/plugins/modeleditor/abstracteditor.cpp
@@ -0,0 +1,942 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "abstracteditor.h"
+
+#include "actionhandler.h"
+#include "diagramsviewmanager.h"
+#include "documentinterface.h"
+#include "dragtool.h"
+#include "editordiagramview.h"
+#include "elementtasks.h"
+#include "extdocumentcontroller.h"
+#include "modeleditor_constants.h"
+#include "modeleditor_plugin.h"
+#include "modelsmanager.h"
+#include "openelementvisitor.h"
+#include "uicontroller.h"
+
+#include "qmt/controller/undocontroller.h"
+#include "qmt/diagram/dpackage.h"
+#include "qmt/diagram_controller/diagramcontroller.h"
+#include "qmt/diagram_controller/dselection.h"
+#include "qmt/diagram_scene/diagramscenemodel.h"
+#include "qmt/diagram_ui/diagram_mime_types.h"
+#include "qmt/diagram_ui/diagramsmanager.h"
+#include "qmt/model/mpackage.h"
+#include "qmt/model/mclass.h"
+#include "qmt/model/mcomponent.h"
+#include "qmt/model/mcanvasdiagram.h"
+#include "qmt/model_controller/modelcontroller.h"
+#include "qmt/model_controller/mselection.h"
+#include "qmt/model_ui/treemodel.h"
+#include "qmt/model_ui/treemodelmanager.h"
+#include "qmt/model_widgets_ui/modeltreeview.h"
+#include "qmt/model_widgets_ui/propertiesview.h"
+#include "qmt/stereotype/shapepaintvisitor.h"
+#include "qmt/stereotype/stereotypecontroller.h"
+#include "qmt/stereotype/stereotypeicon.h"
+#include "qmt/stereotype/toolbar.h"
+#include "qmt/style/style.h"
+#include "qmt/style/stylecontroller.h"
+#include "qmt/tasks/diagramscenecontroller.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/minisplitter.h>
+#include <coreplugin/actionmanager/commandbutton.h>
+#include <utils/styledbar.h>
+#include <utils/qtcassert.h>
+
+#include <QAction>
+#include <QDir>
+#include <QEvent>
+#include <QFileInfo>
+#include <QFrame>
+#include <QHBoxLayout>
+#include <QMap>
+#include <QPainter>
+#include <QPixmap>
+#include <QScrollArea>
+#include <QToolBox>
+#include <QUndoStack>
+#include <QVBoxLayout>
+#include <QWidget>
+#include <QStyleFactory>
+
+#include <QDebug>
+
+namespace ModelEditor {
+namespace Internal {
+
+class AbstractEditor::AbstractEditorPrivate
+{
+public:
+ UiController *uiController = 0;
+ ActionHandler *actionHandler = 0;
+ DocumentInterface *document = 0;
+ qmt::PropertiesView *propertiesView = 0;
+ Core::MiniSplitter *rightSplitter = 0;
+ QWidget *leftGroup = 0;
+ QHBoxLayout *leftGroupLayout = 0;
+ QToolBox *leftToolBox = 0;
+ EditorDiagramView *diagramView = 0;
+ DiagramsViewManager *diagramsViewManager = 0;
+ Core::MiniSplitter *rightHorizSplitter = 0;
+ qmt::ModelTreeView *modelTreeView = 0;
+ qmt::TreeModelManager *modelTreeViewServant = 0;
+ QScrollArea *propertiesScrollArea = 0;
+ QWidget *propertiesGroupWidget = 0;
+ QWidget *toolbar = 0;
+ SelectedArea selectedArea = NOTHING_SELECTED;
+};
+
+AbstractEditor::AbstractEditor(UiController *uiController, ActionHandler *actionHandler,
+ QWidget *parent)
+ : IEditor(parent),
+ d(new AbstractEditorPrivate)
+{
+ d->uiController = uiController;
+ d->actionHandler = actionHandler;
+}
+
+AbstractEditor::~AbstractEditor()
+{
+ if (d->document) {
+ ExtDocumentController *documentController = d->document->documentController();
+ qmt::DiagramsManager *diagramsManager = documentController->getDiagramsManager();
+ qmt::MDiagram *diagram = documentController->getModelController()->findObject<qmt::MDiagram>(d->document->diagramUid());
+ QTC_CHECK(diagram);
+ diagramsManager->unbindDiagramSceneModel(diagram);
+ }
+ delete d->toolbar;
+ delete d;
+}
+
+void AbstractEditor::init(QWidget *parent)
+{
+ // create and configure properties view
+ d->propertiesView = new qmt::PropertiesView(this);
+
+ // create and configure editor ui
+ d->rightSplitter = new Core::MiniSplitter(parent);
+ connect(d->rightSplitter, &QSplitter::splitterMoved,
+ this, &AbstractEditor::onRightSplitterMoved);
+ connect(d->uiController, &UiController::rightSplitterChanged,
+ this, &AbstractEditor::onRightSplitterChanged);
+
+ d->leftGroup = new QWidget(d->rightSplitter);
+ d->leftGroupLayout = new QHBoxLayout(d->leftGroup);
+ d->leftGroupLayout->setContentsMargins(0, 0, 0, 0);
+ d->leftGroupLayout->setSpacing(0);
+
+ d->leftToolBox = new QToolBox(d->leftGroup);
+ // Windows style does not truncate the tab label to a very small width (GTK+ does)
+ static QStyle *windowsStyle = QStyleFactory().create(QStringLiteral("Windows"));
+ if (windowsStyle)
+ d->leftToolBox->setStyle(windowsStyle);
+ // TODO improve this (and the diagram colors) for use with dark theme
+ d->leftToolBox->setStyleSheet(
+ QStringLiteral("QToolBox::tab {"
+ " margin-left: 2px;"
+ " background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
+ " stop: 0 #E1E1E1, stop: 0.4 #DDDDDD,"
+ " stop: 0.5 #D8D8D8, stop: 1.0 #D3D3D3);"
+ " color: #606060;"
+ "}"
+ ""
+ "QToolBox::tab:selected {"
+ " font: italic;"
+ " color: black;"
+ "}"));
+ QFont font;
+ font.setPointSizeF(font.pointSizeF() * 0.8);
+ d->leftToolBox->setFont(font);
+
+ d->diagramView = new EditorDiagramView(d->leftGroup);
+ d->diagramView->setVisible(false);
+
+ d->leftGroupLayout->addWidget(d->leftToolBox, 0);
+ auto frame = new QFrame(d->leftGroup);
+ frame->setFrameShape(QFrame::VLine);
+ d->leftGroupLayout->addWidget(frame, 0);
+ d->leftGroupLayout->addWidget(d->diagramView, 1);
+
+ d->rightHorizSplitter = new Core::MiniSplitter(d->rightSplitter);
+ d->rightHorizSplitter->setOrientation(Qt::Vertical);
+ connect(d->rightHorizSplitter, &QSplitter::splitterMoved,
+ this, &AbstractEditor::onRightHorizSplitterMoved);
+ connect(d->uiController, &UiController::rightHorizSplitterChanged,
+ this, &AbstractEditor::onRightHorizSplitterChanged);
+
+ d->modelTreeView = new qmt::ModelTreeView(d->rightHorizSplitter);
+ d->modelTreeView->setFrameShape(QFrame::NoFrame);
+
+ d->modelTreeViewServant = new qmt::TreeModelManager(this);
+ d->modelTreeViewServant->setModelTreeView(d->modelTreeView);
+
+ d->propertiesScrollArea = new QScrollArea(d->rightHorizSplitter);
+ d->propertiesScrollArea->setFrameShape(QFrame::NoFrame);
+ d->propertiesScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ d->propertiesScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ d->propertiesScrollArea->setWidgetResizable(true);
+
+ d->rightHorizSplitter->insertWidget(0, d->modelTreeView);
+ d->rightHorizSplitter->insertWidget(1, d->propertiesScrollArea);
+ d->rightHorizSplitter->setStretchFactor(0, 2); // magic stretch factors for equal sizing
+ d->rightHorizSplitter->setStretchFactor(1, 3);
+
+ d->rightSplitter->insertWidget(0, d->leftGroup);
+ d->rightSplitter->insertWidget(1, d->rightHorizSplitter);
+ d->rightSplitter->setStretchFactor(0, 1);
+ d->rightSplitter->setStretchFactor(1, 0);
+
+ setWidget(d->rightSplitter);
+
+ // restore splitter sizes afer any stretch factor has been set as fallback
+ if (d->uiController->hasRightSplitterState())
+ d->rightSplitter->restoreState(d->uiController->rightSplitterState());
+ if (d->uiController->hasRightHorizSplitterState())
+ d->rightHorizSplitter->restoreState(d->uiController->rightHorizSplitterState());
+
+ // create and configure toolbar
+ d->toolbar = new QWidget();
+ auto toolbarLayout = new QHBoxLayout(d->toolbar);
+ toolbarLayout->setContentsMargins(0, 0, 0, 0);
+ toolbarLayout->setSpacing(0);
+ toolbarLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));
+ toolbarLayout->addWidget(createToolbarCommandButton(
+ Constants::ACTION_ADD_PACKAGE, [this]() { onAddPackage(); },
+ QIcon(QStringLiteral(":/modelinglib/48x48/package.png")),
+ tr("Add Package"), d->toolbar));
+ toolbarLayout->addWidget(createToolbarCommandButton(
+ Constants::ACTION_ADD_COMPONENT, [this]() { onAddComponent(); },
+ QIcon(QStringLiteral(":/modelinglib/48x48/component.png")),
+ tr("Add Component"), d->toolbar));
+ toolbarLayout->addWidget(createToolbarCommandButton(
+ Constants::ACTION_ADD_CLASS, [this]() { onAddClass(); },
+ QIcon(QStringLiteral(":/modelinglib/48x48/class.png")),
+ tr("Add Class"), d->toolbar));
+ toolbarLayout->addWidget(createToolbarCommandButton(
+ Constants::ACTION_ADD_CANVAS_DIAGRAM, [this]() { onAddCanvasDiagram(); },
+ QIcon(QStringLiteral(":/modelinglib/48x48/canvas-diagram.png")),
+ tr("Add Canvas Diagram"), d->toolbar));
+ toolbarLayout->addItem(new QSpacerItem(20, 0));
+}
+
+void AbstractEditor::setDocument(DocumentInterface *document)
+{
+ QTC_CHECK(!d->document);
+ d->document = document;
+
+ initToolbars();
+
+ ExtDocumentController *documentController = d->document->documentController();
+
+ d->diagramView->setPxNodeController(documentController->pxNodeController());
+
+ QTC_CHECK(!d->diagramsViewManager);
+ d->diagramsViewManager = ModelEditorPlugin::modelsManager()->findDiagramsViewManager(documentController);
+ documentController->getDiagramsManager()->setDiagramsView(d->diagramsViewManager);
+
+ d->propertiesView->setDiagramController(documentController->getDiagramController());
+ d->propertiesView->setModelController(documentController->getModelController());
+ d->propertiesView->setStereotypeController(documentController->getStereotypeController());
+ d->propertiesView->setStyleController(documentController->getStyleController());
+
+ d->modelTreeView->setTreeModel(documentController->getSortedTreeModel());
+ d->modelTreeView->setElementTasks(documentController->elementTasks());
+
+ d->modelTreeViewServant->setTreeModel(documentController->getTreeModel());
+
+ connect(documentController, &qmt::DocumentController::diagramClipboardChanged,
+ this, &AbstractEditor::onDiagramClipboardChanged, Qt::QueuedConnection);
+ connect(documentController->getUndoController()->getUndoStack(), &QUndoStack::canUndoChanged,
+ this, &AbstractEditor::onCanUndoChanged, Qt::QueuedConnection);
+ connect(documentController->getUndoController()->getUndoStack(), &QUndoStack::canRedoChanged,
+ this, &AbstractEditor::onCanRedoChanged, Qt::QueuedConnection);
+ connect(documentController->getTreeModel(), &qmt::TreeModel::modelReset,
+ this, &AbstractEditor::onTreeModelReset, Qt::QueuedConnection);
+ connect(documentController->getDiagramController(), &qmt::DiagramController::modified,
+ this, &AbstractEditor::onDiagramModified, Qt::QueuedConnection);
+ connect(documentController->getDiagramsManager(), &qmt::DiagramsManager::diagramSelectionChanged,
+ this, &AbstractEditor::onDiagramSelectionChanged, Qt::QueuedConnection);
+ connect(documentController->getDiagramsManager(), &qmt::DiagramsManager::diagramActivated,
+ this, &AbstractEditor::onDiagramActivated, Qt::QueuedConnection);
+ connect(documentController->getDiagramSceneController(), &qmt::DiagramSceneController::newElementCreated,
+ this, &AbstractEditor::onNewElementCreated, Qt::QueuedConnection);
+
+ connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged,
+ this, &AbstractEditor::onCurrentEditorChanged, Qt::QueuedConnection);
+
+ connect(d->modelTreeView->selectionModel(), &QItemSelectionModel::selectionChanged,
+ this, &AbstractEditor::onTreeViewSelectionChanged, Qt::QueuedConnection);
+ connect(d->modelTreeView, &qmt::ModelTreeView::treeViewActivated,
+ this, &AbstractEditor::onTreeViewActivated, Qt::QueuedConnection);
+ connect(d->modelTreeView, &QAbstractItemView::doubleClicked,
+ this, &AbstractEditor::onTreeViewDoubleClicked, Qt::QueuedConnection);
+
+ updateSelectedArea(NOTHING_SELECTED);
+
+ // select diagram in model tree view
+ qmt::MDiagram *diagram = documentController->getModelController()->findObject<qmt::MDiagram>(d->document->diagramUid());
+ QTC_CHECK(diagram);
+ QModelIndex modelIndex = documentController->getTreeModel()->getIndex(diagram);
+ if (modelIndex.isValid())
+ d->modelTreeView->selectFromSourceModelIndex(modelIndex);
+}
+
+QWidget *AbstractEditor::toolBar()
+{
+ return d->toolbar;
+}
+
+qmt::MDiagram *AbstractEditor::editorDiagram() const
+{
+ if (!d->diagramView->getDiagramSceneModel())
+ return 0;
+ return d->diagramView->getDiagramSceneModel()->getDiagram();
+}
+
+void AbstractEditor::undo()
+{
+ d->document->documentController()->getUndoController()->getUndoStack()->undo();
+}
+
+void AbstractEditor::redo()
+{
+ d->document->documentController()->getUndoController()->getUndoStack()->redo();
+}
+
+void AbstractEditor::cut()
+{
+ ExtDocumentController *documentController = d->document->documentController();
+
+ switch (d->selectedArea) {
+ case NOTHING_SELECTED:
+ break;
+ case DIAGRAM_SELECTED:
+ documentController->cutFromCurrentDiagram();
+ break;
+ case TREE_VIEW_SELECTED:
+ documentController->cutFromModel(d->modelTreeViewServant->getSelectedObjects());
+ break;
+ }
+}
+
+void AbstractEditor::copy()
+{
+ ExtDocumentController *documentController = d->document->documentController();
+
+ switch (d->selectedArea) {
+ case NOTHING_SELECTED:
+ break;
+ case DIAGRAM_SELECTED:
+ if (documentController->hasCurrentDiagramSelection())
+ documentController->copyFromCurrentDiagram();
+ else
+ documentController->copyCurrentDiagram();
+ break;
+ case TREE_VIEW_SELECTED:
+ documentController->copyFromModel(d->modelTreeViewServant->getSelectedObjects());
+ break;
+ }
+}
+
+void AbstractEditor::paste()
+{
+ ExtDocumentController *documentController = d->document->documentController();
+
+ switch (d->selectedArea) {
+ case NOTHING_SELECTED:
+ break;
+ case DIAGRAM_SELECTED:
+ documentController->pasteIntoCurrentDiagram();
+ break;
+ case TREE_VIEW_SELECTED:
+ documentController->pasteIntoModel(d->modelTreeViewServant->getSelectedObject());
+ break;
+ }
+}
+
+void AbstractEditor::removeSelectedElements()
+{
+ switch (d->selectedArea) {
+ case NOTHING_SELECTED:
+ break;
+ case DIAGRAM_SELECTED:
+ d->document->documentController()->removeFromCurrentDiagram();
+ break;
+ case TREE_VIEW_SELECTED:
+ break;
+ }
+}
+
+void AbstractEditor::deleteSelectedElements()
+{
+ ExtDocumentController *documentController = d->document->documentController();
+
+ switch (d->selectedArea) {
+ case NOTHING_SELECTED:
+ break;
+ case DIAGRAM_SELECTED:
+ documentController->deleteFromCurrentDiagram();
+ break;
+ case TREE_VIEW_SELECTED:
+ documentController->deleteFromModel(d->modelTreeViewServant->getSelectedObjects());
+ break;
+ }
+}
+
+void AbstractEditor::selectAll()
+{
+ d->document->documentController()->selectAllOnCurrentDiagram();
+}
+
+void AbstractEditor::editProperties()
+{
+ d->propertiesView->editSelectedElement();
+}
+
+qmt::MPackage *AbstractEditor::guessSelectedPackage() const
+{
+ qmt::MPackage *package = 0;
+ switch (d->selectedArea) {
+ case NOTHING_SELECTED:
+ package = d->modelTreeViewServant->getSelectedPackage();
+ break;
+ case DIAGRAM_SELECTED:
+ {
+ qmt::DocumentController *documentController = d->document->documentController();
+ qmt::DiagramsManager *diagramsManager = documentController->getDiagramsManager();
+ qmt::MDiagram *diagram = editorDiagram();
+ qmt::DSelection selection = diagramsManager->getDiagramSceneModel(diagram)->getSelectedElements();
+ if (selection.getIndices().size() == 1) {
+ qmt::DPackage *diagramElement = documentController->getDiagramController()->findElement<qmt::DPackage>(selection.getIndices().at(0).getElementKey(), diagram);
+ if (diagramElement)
+ package = documentController->getModelController()->findObject<qmt::MPackage>(diagramElement->getModelUid());
+ }
+ break;
+ }
+ case TREE_VIEW_SELECTED:
+ package = d->modelTreeViewServant->getSelectedPackage();
+ break;
+ }
+ return package;
+}
+
+void AbstractEditor::updateSelectedArea(SelectedArea selectedArea)
+{
+ d->selectedArea = selectedArea;
+
+ qmt::DocumentController *documentController = d->document->documentController();
+ bool canCutCopyDelete = false;
+ bool canRemove = false;
+ bool canPaste = false;
+ bool canSelectAll = false;
+ bool canCopyDiagram = false;
+ QList<qmt::MElement *> propertiesModelElements;
+ QList<qmt::DElement *> propertiesDiagramElements;
+ qmt::MDiagram *propertiesDiagram = 0;
+
+ qmt::MDiagram *activeDiagram = documentController->getDiagramsManager()->getCurrentDiagram();
+ if (activeDiagram != editorDiagram())
+ return;
+ switch (d->selectedArea) {
+ case NOTHING_SELECTED:
+ canSelectAll = activeDiagram && !activeDiagram->getDiagramElements().isEmpty();
+ break;
+ case DIAGRAM_SELECTED:
+ {
+ QTC_ASSERT(activeDiagram, break);
+ bool hasSelection = documentController->getDiagramsManager()->getDiagramSceneModel(activeDiagram)->hasSelection();
+ canCutCopyDelete = hasSelection;
+ canRemove = hasSelection;
+ canPaste = !documentController->isDiagramClipboardEmpty();
+ canSelectAll = !activeDiagram->getDiagramElements().isEmpty();
+ canCopyDiagram = !hasSelection;
+ if (hasSelection) {
+ qmt::DSelection selection = documentController->getDiagramsManager()->getDiagramSceneModel(activeDiagram)->getSelectedElements();
+ if (!selection.isEmpty()) {
+ foreach (qmt::DSelection::Index index, selection.getIndices()) {
+ qmt::DElement *diagramElement = documentController->getDiagramController()->findElement(index.getElementKey(), activeDiagram);
+ if (diagramElement)
+ propertiesDiagramElements.append(diagramElement);
+ }
+ if (!propertiesDiagramElements.isEmpty())
+ propertiesDiagram = activeDiagram;
+ }
+ }
+ break;
+ }
+ case TREE_VIEW_SELECTED:
+ {
+ bool hasSelection = !d->modelTreeViewServant->getSelectedObjects().isEmpty();
+ bool hasSingleSelection = d->modelTreeViewServant->getSelectedObjects().getIndices().size() == 1;
+ canCutCopyDelete = hasSelection && !d->modelTreeViewServant->isRootPackageSelected();
+ canPaste = hasSingleSelection && !documentController->isModelClipboardEmpty();
+ canSelectAll = activeDiagram && !activeDiagram->getDiagramElements().isEmpty();
+ QModelIndexList indexes = d->modelTreeView->getSelectedSourceModelIndexes();
+ if (!indexes.isEmpty()) {
+ foreach (const QModelIndex &propertiesIndex, indexes) {
+ if (propertiesIndex.isValid()) {
+ qmt::MElement *modelElement = documentController->getTreeModel()->getElement(propertiesIndex);
+ if (modelElement)
+ propertiesModelElements.append(modelElement);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ d->actionHandler->cutAction()->setEnabled(canCutCopyDelete);
+ d->actionHandler->copyAction()->setEnabled(canCutCopyDelete || canCopyDiagram);
+ d->actionHandler->pasteAction()->setEnabled(canPaste);
+ d->actionHandler->removeAction()->setEnabled(canRemove);
+ d->actionHandler->deleteAction()->setEnabled(canCutCopyDelete);
+ d->actionHandler->selectAllAction()->setEnabled(canSelectAll);
+
+ if (!propertiesModelElements.isEmpty())
+ showProperties(propertiesModelElements);
+ else if (!propertiesDiagramElements.isEmpty())
+ showProperties(propertiesDiagram, propertiesDiagramElements);
+ else
+ clearProperties();
+}
+
+void AbstractEditor::showProperties(const QList<qmt::MElement *> &modelElements)
+{
+ if (modelElements != d->propertiesView->getSelectedModelElements()) {
+ clearProperties();
+ if (modelElements.size() > 0) {
+ d->propertiesView->setSelectedModelElements(modelElements);
+ d->propertiesGroupWidget = d->propertiesView->getWidget();
+ d->propertiesScrollArea->setWidget(d->propertiesGroupWidget);
+ }
+ }
+}
+
+void AbstractEditor::showProperties(qmt::MDiagram *diagram,
+ const QList<qmt::DElement *> &diagramElements)
+{
+ if (diagram != d->propertiesView->getSelectedDiagram()
+ || diagramElements != d->propertiesView->getSelectedDiagramElements())
+ {
+ clearProperties();
+ if (diagram && diagramElements.size() > 0) {
+ d->propertiesView->setSelectedDiagramElements(diagramElements, diagram);
+ d->propertiesGroupWidget = d->propertiesView->getWidget();
+ d->propertiesScrollArea->setWidget(d->propertiesGroupWidget);
+ }
+ }
+}
+
+void AbstractEditor::clearProperties()
+{
+ d->propertiesView->clearSelection();
+ if (d->propertiesGroupWidget) {
+ QWidget *scrollWidget = d->propertiesScrollArea->takeWidget();
+ Q_UNUSED(scrollWidget); // avoid warning in release mode
+ QTC_CHECK(scrollWidget == d->propertiesGroupWidget);
+ d->propertiesGroupWidget->deleteLater();
+ d->propertiesGroupWidget = 0;
+ }
+}
+
+void AbstractEditor::openDiagram(qmt::MDiagram *diagram)
+{
+ QTC_ASSERT(diagram, return);
+ d->document->documentController()->getDiagramsManager()->openDiagram(diagram);
+}
+
+void AbstractEditor::showDiagram(qmt::MDiagram *diagram)
+{
+ if (diagram) {
+ qmt::DiagramSceneModel *diagramSceneModel = d->document->documentController()->getDiagramsManager()->bindDiagramSceneModel(diagram);
+ QTC_ASSERT(diagramSceneModel, return);
+ QTC_ASSERT(d->diagramView, return);
+ d->diagramView->setDiagramSceneModel(diagramSceneModel);
+ d->diagramView->setVisible(true);
+ }
+}
+
+void AbstractEditor::expandModelTreeToDepth(int depth)
+{
+ d->modelTreeView->expandToDepth(depth);
+}
+
+QWidget *AbstractEditor::createToolbarCommandButton(const Core::Id &id, const std::function<void()> &slot,
+ const QIcon &icon, const QString &toolTipBase,
+ QWidget *parent)
+{
+ auto button = new Core::CommandButton(id, parent);
+ button->setIcon(icon);
+ button->setToolTipBase(toolTipBase);
+ connect(button, &Core::CommandButton::clicked, this, slot);
+ return button;
+}
+
+/*!
+ Tries to change the \a button icon to the icon specified by \a name
+ from the current theme. Returns \c true if icon is updated, \c false
+ otherwise.
+*/
+
+bool AbstractEditor::updateButtonIconByTheme(QAbstractButton *button, const QString &name)
+{
+ QTC_ASSERT(button, return false);
+ QTC_ASSERT(!name.isEmpty(), return false);
+
+ if (QIcon::hasThemeIcon(name)) {
+ button->setIcon(QIcon::fromTheme(name));
+ return true;
+ }
+
+ return false;
+}
+
+void AbstractEditor::onAddPackage()
+{
+ ExtDocumentController *documentController = d->document->documentController();
+
+ qmt::MPackage *package = documentController->createNewPackage(d->modelTreeViewServant->getSelectedPackage());
+ d->modelTreeView->selectFromSourceModelIndex(documentController->getTreeModel()->getIndex(package));
+ metaObject()->invokeMethod(this, "onEditSelectedElement", Qt::QueuedConnection);
+}
+
+void AbstractEditor::onAddComponent()
+{
+ ExtDocumentController *documentController = d->document->documentController();
+
+ qmt::MComponent *component = documentController->createNewComponent(d->modelTreeViewServant->getSelectedPackage());
+ d->modelTreeView->selectFromSourceModelIndex(documentController->getTreeModel()->getIndex(component));
+ metaObject()->invokeMethod(this, "onEditSelectedElement", Qt::QueuedConnection);
+}
+
+void AbstractEditor::onAddClass()
+{
+ ExtDocumentController *documentController = d->document->documentController();
+
+ qmt::MClass *klass = documentController->createNewClass(d->modelTreeViewServant->getSelectedPackage());
+ d->modelTreeView->selectFromSourceModelIndex(documentController->getTreeModel()->getIndex(klass));
+ metaObject()->invokeMethod(this, "onEditSelectedElement", Qt::QueuedConnection);
+}
+
+void AbstractEditor::onAddCanvasDiagram()
+{
+ ExtDocumentController *documentController = d->document->documentController();
+
+ qmt::MDiagram *diagram = documentController->createNewCanvasDiagram(d->modelTreeViewServant->getSelectedPackage());
+ d->modelTreeView->selectFromSourceModelIndex(documentController->getTreeModel()->getIndex(diagram));
+ metaObject()->invokeMethod(this, "onEditSelectedElement", Qt::QueuedConnection);
+}
+
+void AbstractEditor::onCurrentEditorChanged(Core::IEditor *editor)
+{
+ if (this == editor) {
+ QUndoStack *undo_stack = d->document->documentController()->getUndoController()->getUndoStack();
+ d->actionHandler->undoAction()->setDisabled(!undo_stack->canUndo());
+ d->actionHandler->redoAction()->setDisabled(!undo_stack->canRedo());
+
+ updateSelectedArea(NOTHING_SELECTED);
+ }
+}
+
+void AbstractEditor::onCanUndoChanged(bool canUndo)
+{
+ if (this == Core::EditorManager::currentEditor())
+ d->actionHandler->undoAction()->setEnabled(canUndo);
+}
+
+void AbstractEditor::onCanRedoChanged(bool canRedo)
+{
+ if (this == Core::EditorManager::currentEditor())
+ d->actionHandler->redoAction()->setEnabled(canRedo);
+}
+
+void AbstractEditor::onTreeModelReset()
+{
+ updateSelectedArea(NOTHING_SELECTED);
+}
+
+void AbstractEditor::onTreeViewSelectionChanged(const QItemSelection &selected,
+ const QItemSelection &deselected)
+{
+ Q_UNUSED(selected);
+ Q_UNUSED(deselected);
+
+ updateSelectedArea(TREE_VIEW_SELECTED);
+}
+
+void AbstractEditor::onTreeViewActivated()
+{
+ updateSelectedArea(TREE_VIEW_SELECTED);
+}
+
+void AbstractEditor::onTreeViewDoubleClicked(const QModelIndex &index)
+{
+ ExtDocumentController *documentController = d->document->documentController();
+
+ QModelIndex treeModelIndex = d->modelTreeView->mapToSourceModelIndex(index);
+ qmt::MElement *melement = documentController->getTreeModel()->getElement(treeModelIndex);
+ // double click on package is already used for toggeling tree
+ if (melement && !dynamic_cast<qmt::MPackage *>(melement))
+ documentController->elementTasks()->openElement(melement);
+}
+
+void AbstractEditor::onCurrentDiagramChanged(const qmt::MDiagram *diagram)
+{
+ if (diagram) {
+ QTC_CHECK(diagram == d->document->documentController()->getDiagramsManager()->getCurrentDiagram());
+ updateSelectedArea(DIAGRAM_SELECTED);
+ } else {
+ updateSelectedArea(NOTHING_SELECTED);
+ }
+}
+
+void AbstractEditor::onDiagramActivated(const qmt::MDiagram *diagram)
+{
+ Q_UNUSED(diagram);
+
+ updateSelectedArea(DIAGRAM_SELECTED);
+}
+
+void AbstractEditor::onDiagramClipboardChanged(bool isEmpty)
+{
+ Q_UNUSED(isEmpty);
+
+ if (this == Core::EditorManager::currentEditor())
+ updateSelectedArea(d->selectedArea);
+}
+
+void AbstractEditor::onNewElementCreated(qmt::DElement *element, qmt::MDiagram *diagram)
+{
+ if (diagram == editorDiagram()) {
+ ExtDocumentController *documentController = d->document->documentController();
+
+ documentController->getDiagramsManager()->getDiagramSceneModel(diagram)->selectElement(element);
+ qmt::MElement *melement = documentController->getModelController()->findElement(element->getModelUid());
+ if (!(melement && melement->getFlags().testFlag(qmt::MElement::REVERSE_ENGINEERED)))
+ metaObject()->invokeMethod(this, "onEditSelectedElement", Qt::QueuedConnection);
+ }
+}
+
+void AbstractEditor::onDiagramSelectionChanged(const qmt::MDiagram *diagram)
+{
+ if (diagram == editorDiagram())
+ updateSelectedArea(DIAGRAM_SELECTED);
+}
+
+void AbstractEditor::onDiagramModified(const qmt::MDiagram *diagram)
+{
+ Q_UNUSED(diagram);
+
+ updateSelectedArea(d->selectedArea);
+}
+
+void AbstractEditor::onEditSelectedElement()
+{
+ // TODO introduce similar method for selected elements in model tree
+ // currently this method is called on adding new elements in model tree
+ // but the method is a no-op in that case.
+ qmt::MDiagram *diagram = d->propertiesView->getSelectedDiagram();
+ QList<qmt::DElement *> elements = d->propertiesView->getSelectedDiagramElements();
+ if (diagram && !elements.isEmpty()) {
+ qmt::DElement *element = elements.at(0);
+ if (element) {
+ qmt::DiagramSceneModel *diagramSceneModel = d->document->documentController()->getDiagramsManager()->getDiagramSceneModel(diagram);
+ if (diagramSceneModel->isElementEditable(element)) {
+ diagramSceneModel->editElement(element);
+ return;
+ }
+ }
+ d->propertiesView->editSelectedElement();
+ }
+}
+
+void AbstractEditor::onRightSplitterMoved(int pos, int index)
+{
+ Q_UNUSED(pos);
+ Q_UNUSED(index);
+
+ d->uiController->onRightSplitterChanged(d->rightSplitter->saveState());
+}
+
+void AbstractEditor::onRightSplitterChanged(const QByteArray &state)
+{
+ d->rightSplitter->restoreState(state);
+}
+
+void AbstractEditor::onRightHorizSplitterMoved(int pos, int index)
+{
+ Q_UNUSED(pos);
+ Q_UNUSED(index);
+
+ d->uiController->onRightHorizSplitterChanged(d->rightHorizSplitter->saveState());
+}
+
+void AbstractEditor::onRightHorizSplitterChanged(const QByteArray &state)
+{
+ d->rightHorizSplitter->restoreState(state);
+}
+
+void AbstractEditor::initToolbars()
+{
+ QHash<QString, QWidget *> toolBars;
+ // TODO add toolbars sorted by prio
+ qmt::DocumentController *documentController = d->document->documentController();
+ qmt::StereotypeController *stereotypeController = documentController->getStereotypeController();
+ foreach (const qmt::Toolbar &toolbar, stereotypeController->getToolbars()) {
+ QWidget *toolBar = toolBars.value(toolbar.getId());
+ QLayout *toolBarLayout = 0;
+ if (!toolBar) {
+ toolBar = new QWidget(d->leftToolBox);
+ toolBarLayout = new QVBoxLayout(toolBar);
+ toolBarLayout->setContentsMargins(2, 2, 2, 2);
+ toolBarLayout->setSpacing(6);
+ d->leftToolBox->addItem(toolBar, toolbar.getId());
+ toolBars.insert(toolbar.getId(), toolBar);
+ } else {
+ toolBarLayout = toolBar->layout();
+ QTC_ASSERT(toolBarLayout, return);
+ }
+ foreach (const qmt::Toolbar::Tool &tool, toolbar.getTools()) {
+ switch (tool._tool_type) {
+ case qmt::Toolbar::TOOLTYPE_TOOL:
+ {
+ QString iconPath;
+ qmt::StereotypeIcon::Element stereotypeIconElement = qmt::StereotypeIcon::ELEMENT_ANY;
+ qmt::StyleEngine::ElementType styleEngineElementType = qmt::StyleEngine::TYPE_OTHER;
+ if (tool._element_type == QLatin1String(qmt::ELEMENT_TYPE_PACKAGE)) {
+ iconPath = QStringLiteral(":/modelinglib/48x48/package.png");
+ stereotypeIconElement = qmt::StereotypeIcon::ELEMENT_PACKAGE;
+ styleEngineElementType = qmt::StyleEngine::TYPE_PACKAGE;
+ } else if (tool._element_type == QLatin1String(qmt::ELEMENT_TYPE_COMPONENT)) {
+ iconPath = QStringLiteral(":/modelinglib/48x48/component.png");
+ stereotypeIconElement = qmt::StereotypeIcon::ELEMENT_COMPONENT;
+ styleEngineElementType = qmt::StyleEngine::TYPE_COMPONENT;
+ } else if (tool._element_type == QLatin1String(qmt::ELEMENT_TYPE_CLASS)) {
+ iconPath = QStringLiteral(":/modelinglib/48x48/class.png");
+ stereotypeIconElement = qmt::StereotypeIcon::ELEMENT_CLASS;
+ styleEngineElementType = qmt::StyleEngine::TYPE_CLASS;
+ } else if (tool._element_type == QLatin1String(qmt::ELEMENT_TYPE_ITEM)) {
+ iconPath = QStringLiteral(":/modelinglib/48x48/item.png");
+ stereotypeIconElement = qmt::StereotypeIcon::ELEMENT_ITEM;
+ styleEngineElementType = qmt::StyleEngine::TYPE_ITEM;
+ } else if (tool._element_type == QLatin1String(qmt::ELEMENT_TYPE_ANNOTATION)) {
+ iconPath = QStringLiteral(":/modelinglib/48x48/annotation.png");
+ styleEngineElementType = qmt::StyleEngine::TYPE_ANNOTATION;
+ } else if (tool._element_type == QLatin1String(qmt::ELEMENT_TYPE_BOUNDARY)) {
+ iconPath = QStringLiteral(":/modelinglib/48x48/boundary.png");
+ styleEngineElementType = qmt::StyleEngine::TYPE_BOUNDARY;
+ }
+ QIcon icon;
+ if (!tool._stereotype.isEmpty() && stereotypeIconElement != qmt::StereotypeIcon::ELEMENT_ANY) {
+ const qmt::Style *style = documentController->getStyleController()->adaptStyle(styleEngineElementType);
+ icon = stereotypeController->createIcon(
+ stereotypeIconElement, QStringList() << tool._stereotype,
+ QString(), style, QSize(48, 48), QMarginsF(3.0, 2.0, 3.0, 4.0));
+ }
+ if (icon.isNull())
+ icon = QIcon(iconPath);
+ if (!icon.isNull()) {
+ toolBarLayout->addWidget(new DragTool(icon, tool._name, tool._element_type,
+ tool._stereotype, toolBar));
+ }
+ break;
+ }
+ case qmt::Toolbar::TOOLTYPE_SEPARATOR:
+ {
+ auto horizLine1 = new QFrame(d->leftToolBox);
+ horizLine1->setFrameShape(QFrame::HLine);
+ toolBarLayout->addWidget(horizLine1);
+ break;
+ }
+ }
+ }
+ }
+
+ // fallback if no toolbar was defined
+ if (!toolBars.isEmpty()) {
+ QString generalId = QStringLiteral("General");
+ auto toolBar = new QWidget(d->leftToolBox);
+ auto toolBarLayout = new QVBoxLayout(toolBar);
+ toolBarLayout->setContentsMargins(2, 2, 2, 2);
+ toolBarLayout->setSpacing(6);
+ d->leftToolBox->insertItem(0, toolBar, generalId);
+ toolBars.insert(generalId, toolBar);
+ toolBarLayout->addWidget(
+ new DragTool(QIcon(QStringLiteral(":/modelinglib/48x48/package.png")),
+ tr("Package"), QLatin1String(qmt::ELEMENT_TYPE_PACKAGE),
+ QString(), toolBar));
+ toolBarLayout->addWidget(
+ new DragTool(QIcon(QStringLiteral(":/modelinglib/48x48/component.png")),
+ tr("Component"), QLatin1String(qmt::ELEMENT_TYPE_COMPONENT),
+ QString(), toolBar));
+ toolBarLayout->addWidget(
+ new DragTool(QIcon(QStringLiteral(":/modelinglib/48x48/class.png")),
+ tr("Class"), QLatin1String(qmt::ELEMENT_TYPE_CLASS),
+ QString(), toolBar));
+ toolBarLayout->addWidget(
+ new DragTool(QIcon(QStringLiteral(":/modelinglib/48x48/item.png")),
+ tr("Item"), QLatin1String(qmt::ELEMENT_TYPE_ITEM),
+ QString(), toolBar));
+ auto horizLine1 = new QFrame(d->leftToolBox);
+ horizLine1->setFrameShape(QFrame::HLine);
+ toolBarLayout->addWidget(horizLine1);
+ toolBarLayout->addWidget(
+ new DragTool(QIcon(QStringLiteral(":/modelinglib/48x48/annotation.png")),
+ tr("Annotation"), QLatin1String(qmt::ELEMENT_TYPE_ANNOTATION),
+ QString(), toolBar));
+ toolBarLayout->addWidget(
+ new DragTool(QIcon(QStringLiteral(":/modelinglib/48x48/boundary.png")),
+ tr("Boundary"), QLatin1String(qmt::ELEMENT_TYPE_BOUNDARY),
+ QString(), toolBar));
+ }
+
+ // add stretch to all layouts and calculate width of tool bar
+ int maxWidth = 48;
+ foreach (QWidget *toolBar, toolBars) {
+ QTC_ASSERT(toolBar, continue);
+ auto layout = dynamic_cast<QBoxLayout *>(toolBar->layout());
+ QTC_ASSERT(layout, continue);
+ layout->addStretch(1);
+ toolBar->adjustSize();
+ if (maxWidth < toolBar->width())
+ maxWidth = toolBar->width();
+ }
+ d->leftToolBox->setFixedWidth(maxWidth);
+
+ d->leftToolBox->setCurrentIndex(0);
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/abstracteditor.h b/src/plugins/modeleditor/abstracteditor.h
new file mode 100644
index 00000000000..b1e0b14fcd1
--- /dev/null
+++ b/src/plugins/modeleditor/abstracteditor.h
@@ -0,0 +1,144 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef ABSTRACTEDITOR_H
+#define ABSTRACTEDITOR_H
+
+#include <coreplugin/editormanager/ieditor.h>
+
+#include <QAbstractButton>
+
+#include <functional>
+
+QT_BEGIN_NAMESPACE
+class QItemSelection;
+QT_END_NAMESPACE
+
+namespace qmt {
+class MElement;
+class MPackage;
+class MDiagram;
+class DElement;
+class DocumentController;
+}
+
+namespace ModelEditor {
+namespace Internal {
+
+class UiController;
+class ActionHandler;
+class DiagramsViewManager;
+class DocumentInterface;
+
+enum SelectedArea {
+ NOTHING_SELECTED,
+ DIAGRAM_SELECTED,
+ TREE_VIEW_SELECTED
+};
+
+class AbstractEditor :
+ public Core::IEditor
+{
+ Q_OBJECT
+ class AbstractEditorPrivate;
+
+public:
+ explicit AbstractEditor(UiController *uiController, ActionHandler *actionHandler,
+ QWidget *parent = 0);
+ ~AbstractEditor();
+
+protected:
+ void init(QWidget *parent);
+ void setDocument(DocumentInterface *document);
+
+public:
+ QWidget *toolBar() override;
+ qmt::MDiagram *editorDiagram() const;
+ void undo();
+ void redo();
+ void cut();
+ void copy();
+ void paste();
+ void removeSelectedElements();
+ void deleteSelectedElements();
+ void selectAll();
+ void editProperties();
+ qmt::MPackage *guessSelectedPackage() const;
+
+protected:
+ void updateSelectedArea(SelectedArea selectedArea);
+ void showProperties(const QList<qmt::MElement *> &modelElements);
+ void showProperties(qmt::MDiagram *diagram, const QList<qmt::DElement *> &diagramElements);
+ void clearProperties();
+ void openDiagram(qmt::MDiagram *diagram);
+ void showDiagram(qmt::MDiagram *diagram);
+ void expandModelTreeToDepth(int depth);
+ QWidget *createToolbarCommandButton(const Core::Id &id, const std::function<void()> &slot,
+ const QIcon &icon,
+ const QString &toolTipBase, QWidget *parent);
+ bool updateButtonIconByTheme(QAbstractButton *button, const QString &name);
+
+private slots:
+ void onAddPackage();
+ void onAddComponent();
+ void onAddClass();
+ void onAddCanvasDiagram();
+ void onCurrentEditorChanged(Core::IEditor *editor);
+ void onCanUndoChanged(bool canUndo);
+ void onCanRedoChanged(bool canRedo);
+ void onTreeModelReset();
+ void onTreeViewSelectionChanged(const QItemSelection &selected,
+ const QItemSelection &deselected);
+ void onTreeViewActivated();
+ void onTreeViewDoubleClicked(const QModelIndex &index);
+ void onCurrentDiagramChanged(const qmt::MDiagram *diagram);
+ void onDiagramActivated(const qmt::MDiagram *diagram);
+ void onDiagramClipboardChanged(bool isEmpty);
+ void onNewElementCreated(qmt::DElement *element, qmt::MDiagram *diagram);
+ void onDiagramSelectionChanged(const qmt::MDiagram *diagram);
+ void onDiagramModified(const qmt::MDiagram *diagram);
+ void onEditSelectedElement();
+
+ void onRightSplitterMoved(int pos, int index);
+ void onRightSplitterChanged(const QByteArray &state);
+ void onRightHorizSplitterMoved(int pos, int index);
+ void onRightHorizSplitterChanged(const QByteArray &state);
+
+private:
+ void initToolbars();
+
+private:
+ AbstractEditorPrivate *d;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // ABSTRACTEDITOR_H
diff --git a/src/plugins/modeleditor/actionhandler.cpp b/src/plugins/modeleditor/actionhandler.cpp
new file mode 100644
index 00000000000..5554a8b3c16
--- /dev/null
+++ b/src/plugins/modeleditor/actionhandler.cpp
@@ -0,0 +1,225 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "actionhandler.h"
+
+#include "modeleditor_constants.h"
+#include "abstracteditor.h"
+
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/actionmanager/actioncontainer.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/icore.h>
+
+#include <QAction>
+#include <QShortcut>
+
+namespace ModelEditor {
+namespace Internal {
+
+class ActionHandler::ActionHandlerPrivate {
+public:
+ Core::Context context;
+ QAction *undoAction = 0;
+ QAction *redoAction = 0;
+ QAction *cutAction = 0;
+ QAction *copyAction = 0;
+ QAction *pasteAction = 0;
+ QAction *removeAction = 0;
+ QAction *deleteAction = 0;
+ QAction *selectAllAction = 0;
+};
+
+ActionHandler::ActionHandler(const Core::Context &context, QObject *parent)
+ : QObject(parent),
+ d(new ActionHandlerPrivate)
+{
+ d->context = context;
+}
+
+ActionHandler::~ActionHandler()
+{
+ delete d;
+}
+
+QAction *ActionHandler::undoAction() const
+{
+ return d->undoAction;
+}
+
+QAction *ActionHandler::redoAction() const
+{
+ return d->redoAction;
+}
+
+QAction *ActionHandler::cutAction() const
+{
+ return d->cutAction;
+}
+
+QAction *ActionHandler::copyAction() const
+{
+ return d->copyAction;
+}
+
+QAction *ActionHandler::pasteAction() const
+{
+ return d->pasteAction;
+}
+
+QAction *ActionHandler::removeAction() const
+{
+ return d->removeAction;
+}
+
+QAction *ActionHandler::deleteAction() const
+{
+ return d->deleteAction;
+}
+
+QAction *ActionHandler::selectAllAction() const
+{
+ return d->selectAllAction;
+}
+
+void ActionHandler::createActions()
+{
+ Core::ActionContainer *medit = Core::ActionManager::actionContainer(Core::Constants::M_EDIT);
+
+ d->undoAction = registerCommand(Core::Constants::UNDO, [this]() { undo(); })->action();
+ d->redoAction = registerCommand(Core::Constants::REDO, [this]() { redo(); })->action();
+ d->cutAction = registerCommand(Core::Constants::CUT, [this]() { cut(); })->action();
+ d->copyAction = registerCommand(Core::Constants::COPY, [this]() { copy(); })->action();
+ d->pasteAction = registerCommand(Core::Constants::PASTE, [this]() { paste(); })->action();
+ Core::Command *removeCommand = registerCommand(
+ Constants::REMOVE_SELECTED_ELEMENTS, [this]() { removeSelectedElements(); }, true,
+ tr("&Remove"), QKeySequence::Delete);
+ medit->addAction(removeCommand, Core::Constants::G_EDIT_COPYPASTE);
+ d->removeAction = removeCommand->action();
+ Core::Command *deleteCommand = registerCommand(
+ Constants::DELETE_SELECTED_ELEMENTS, [this]() { deleteSelectedElements(); }, true,
+ tr("&Delete"), QKeySequence(QStringLiteral("Ctrl+D")));
+ medit->addAction(deleteCommand, Core::Constants::G_EDIT_COPYPASTE);
+ d->deleteAction = deleteCommand->action();
+ d->selectAllAction = registerCommand(Core::Constants::SELECTALL, [this]() { selectAll(); })->action();
+ registerCommand(Constants::ACTION_ADD_PACKAGE, 0);
+ registerCommand(Constants::ACTION_ADD_COMPONENT, 0);
+ registerCommand(Constants::ACTION_ADD_CLASS, 0);
+ registerCommand(Constants::ACTION_ADD_CANVAS_DIAGRAM, 0);
+}
+
+void ActionHandler::createEditPropertiesShortcut(const Core::Id &shortcutId)
+{
+ auto editAction = new QAction(tr("Edit selected element in properties view"), Core::ICore::mainWindow());
+ Core::Command *editCommand = Core::ActionManager::registerAction(
+ editAction, shortcutId, d->context);
+ editCommand->setDefaultKeySequence(QKeySequence(tr("F2")));
+ connect(editAction, &QAction::triggered, this, &ActionHandler::onEditProperties);
+}
+
+void ActionHandler::undo()
+{
+ auto editor = dynamic_cast<AbstractEditor *>(Core::EditorManager::currentEditor());
+ if (editor)
+ editor->undo();
+}
+
+void ActionHandler::redo()
+{
+ auto editor = dynamic_cast<AbstractEditor *>(Core::EditorManager::currentEditor());
+ if (editor)
+ editor->redo();
+}
+
+void ActionHandler::cut()
+{
+ auto editor = dynamic_cast<AbstractEditor *>(Core::EditorManager::currentEditor());
+ if (editor)
+ editor->cut();
+}
+
+void ActionHandler::copy()
+{
+ auto editor = dynamic_cast<AbstractEditor *>(Core::EditorManager::currentEditor());
+ if (editor)
+ editor->copy();
+}
+
+void ActionHandler::paste()
+{
+ auto editor = dynamic_cast<AbstractEditor *>(Core::EditorManager::currentEditor());
+ if (editor)
+ editor->paste();
+}
+
+void ActionHandler::removeSelectedElements()
+{
+ auto editor = dynamic_cast<AbstractEditor *>(Core::EditorManager::currentEditor());
+ if (editor)
+ editor->removeSelectedElements();
+}
+
+void ActionHandler::deleteSelectedElements()
+{
+ auto editor = dynamic_cast<AbstractEditor *>(Core::EditorManager::currentEditor());
+ if (editor)
+ editor->deleteSelectedElements();
+}
+
+void ActionHandler::selectAll()
+{
+ auto editor = dynamic_cast<AbstractEditor *>(Core::EditorManager::currentEditor());
+ if (editor)
+ editor->selectAll();
+}
+
+void ActionHandler::onEditProperties()
+{
+ auto editor = dynamic_cast<AbstractEditor *>(Core::EditorManager::currentEditor());
+ if (editor)
+ editor->editProperties();
+}
+
+Core::Command *ActionHandler::registerCommand(const Core::Id &id, const std::function<void()> &slot,
+ bool scriptable, const QString &title,
+ const QKeySequence &keySequence)
+{
+ auto action = new QAction(title, this);
+ Core::Command *command = Core::ActionManager::registerAction(action, id, d->context, scriptable);
+ if (!keySequence.isEmpty())
+ command->setDefaultKeySequence(keySequence);
+ if (slot)
+ connect(action, &QAction::triggered, this, slot);
+ return command;
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/actionhandler.h b/src/plugins/modeleditor/actionhandler.h
new file mode 100644
index 00000000000..a2fa147c2e2
--- /dev/null
+++ b/src/plugins/modeleditor/actionhandler.h
@@ -0,0 +1,98 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef ACTIONHANDLER_H
+#define ACTIONHANDLER_H
+
+#include <QObject>
+
+#include <coreplugin/icontext.h>
+
+#include <functional>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+QT_END_NAMESPACE
+
+namespace Core {
+class ActionContainer;
+class Command;
+}
+
+namespace ModelEditor {
+namespace Internal {
+
+class ActionHandler :
+ public QObject
+{
+ Q_OBJECT
+ class ActionHandlerPrivate;
+
+public:
+ ActionHandler(const Core::Context &context, QObject *parent = 0);
+ ~ActionHandler();
+
+public:
+ QAction *undoAction() const;
+ QAction *redoAction() const;
+ QAction *cutAction() const;
+ QAction *copyAction() const;
+ QAction *pasteAction() const;
+ QAction *removeAction() const;
+ QAction *deleteAction() const;
+ QAction *selectAllAction() const;
+
+ void createActions();
+ void createEditPropertiesShortcut(const Core::Id &shortcutId);
+
+private slots:
+ void undo();
+ void redo();
+ void cut();
+ void copy();
+ void paste();
+ void removeSelectedElements();
+ void deleteSelectedElements();
+ void selectAll();
+ void onEditProperties();
+
+private:
+ Core::Command *registerCommand(const Core::Id &id, const std::function<void()> &slot,
+ bool scriptable = true, const QString &title = QString(),
+ const QKeySequence &keySequence = QKeySequence());
+
+private:
+ ActionHandlerPrivate *d;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // ACTIONHANDLER_H
diff --git a/src/plugins/modeleditor/classviewcontroller.cpp b/src/plugins/modeleditor/classviewcontroller.cpp
new file mode 100644
index 00000000000..3339e32aebe
--- /dev/null
+++ b/src/plugins/modeleditor/classviewcontroller.cpp
@@ -0,0 +1,101 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "classviewcontroller.h"
+
+#include <cpptools/cppmodelmanager.h>
+#include <cpptools/cpptoolsreuse.h>
+#include <cplusplus/Overview.h>
+#include <cplusplus/LookupContext.h>
+
+namespace ModelEditor {
+namespace Internal {
+
+ClassViewController::ClassViewController(QObject *parent)
+ : QObject(parent)
+{
+}
+
+QSet<QString> ClassViewController::findClassDeclarations(const QString &fileName)
+{
+ QSet<QString> classNames;
+
+ CppTools::CppModelManager *cppModelManager = CppTools::CppModelManager::instance();
+ CPlusPlus::Snapshot snapshot = cppModelManager->snapshot();
+
+ // scan original file
+ CPlusPlus::Document::Ptr document = snapshot.document(fileName);
+ if (!document.isNull())
+ appendClassDeclarationsFromDocument(document, &classNames);
+
+ QString otherFileName = CppTools::correspondingHeaderOrSource(fileName);
+
+ // scan other file
+ document = snapshot.document(otherFileName);
+ if (!document.isNull())
+ appendClassDeclarationsFromDocument(document, &classNames);
+
+ return classNames;
+}
+
+void ClassViewController::appendClassDeclarationsFromDocument(CPlusPlus::Document::Ptr document,
+ QSet<QString> *classNames)
+{
+ int total = document->globalSymbolCount();
+ for (int i = 0; i < total; ++i) {
+ CPlusPlus::Symbol *symbol = document->globalSymbolAt(i);
+ appendClassDeclarationsFromSymbol(symbol, classNames);
+ }
+}
+
+void ClassViewController::appendClassDeclarationsFromSymbol(CPlusPlus::Symbol *symbol,
+ QSet<QString> *classNames)
+{
+ if (symbol->isClass()) {
+ CPlusPlus::Overview overview;
+ QString className = overview.prettyName(
+ CPlusPlus::LookupContext::fullyQualifiedName(symbol));
+ // Ignore private class created by Q_OBJECT macro
+ if (!className.endsWith(QStringLiteral("::QPrivateSignal")))
+ classNames->insert(className);
+ }
+
+ if (symbol->isScope()) {
+ CPlusPlus::Scope *scope = symbol->asScope();
+ int total = scope->memberCount();
+ for (int i = 0; i < total; ++i) {
+ CPlusPlus::Symbol *member = scope->memberAt(i);
+ appendClassDeclarationsFromSymbol(member, classNames);
+ }
+ }
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/classviewcontroller.h b/src/plugins/modeleditor/classviewcontroller.h
new file mode 100644
index 00000000000..508d5ee1a92
--- /dev/null
+++ b/src/plugins/modeleditor/classviewcontroller.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef CLASSVIEWCONTROLLER_H
+#define CLASSVIEWCONTROLLER_H
+
+#include <QObject>
+
+#include <cplusplus/CppDocument.h>
+
+namespace ModelEditor {
+namespace Internal {
+
+class ClassViewController :
+ public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit ClassViewController(QObject *parent = 0);
+ ~ClassViewController() = default;
+
+ QSet<QString> findClassDeclarations(const QString &fileName);
+ void appendClassDeclarationsFromDocument(CPlusPlus::Document::Ptr document,
+ QSet<QString> *classNames);
+ void appendClassDeclarationsFromSymbol(CPlusPlus::Symbol *symbol, QSet<QString> *class_names);
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // CLASSVIEWCONTROLLER_H
diff --git a/src/plugins/modeleditor/componentviewcontroller.cpp b/src/plugins/modeleditor/componentviewcontroller.cpp
new file mode 100644
index 00000000000..e313a336229
--- /dev/null
+++ b/src/plugins/modeleditor/componentviewcontroller.cpp
@@ -0,0 +1,439 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "componentviewcontroller.h"
+
+#include "pxnodeutilities.h"
+
+#include "qmt/controller/namecontroller.h"
+#include "qmt/model_controller/mchildrenvisitor.h"
+#include "qmt/model_controller/modelcontroller.h"
+#include "qmt/model/mcomponent.h"
+#include "qmt/model/mdependency.h"
+#include "qmt/model/mpackage.h"
+#include "qmt/tasks/diagramscenecontroller.h"
+
+#include <cpptools/cppmodelmanager.h>
+#include <cplusplus/CppDocument.h>
+
+#include <projectexplorer/session.h>
+#include <projectexplorer/projectnodes.h>
+#include <projectexplorer/project.h>
+
+#include <utils/qtcassert.h>
+
+#include <QFileInfo>
+
+// TODO this class is experimental and not finished. Code needs fixes and to be cleaned up!
+
+namespace ModelEditor {
+namespace Internal {
+
+class FindComponentFromFilePath :
+ public qmt::MChildrenVisitor
+{
+public:
+ void setFilePath(const QString &filePath);
+ qmt::MComponent *component() const { return m_bestComponent; }
+ void visitMComponent(qmt::MComponent *component);
+
+private:
+ QString m_elementName;
+ QStringList m_elementsPath;
+ int m_maxPathLength = 0;
+ qmt::MComponent *m_bestComponent = 0;
+};
+
+void FindComponentFromFilePath::setFilePath(const QString &filePath)
+{
+ m_elementName = qmt::NameController::convertFileNameToElementName(filePath);
+ QFileInfo fileInfo(filePath);
+ m_elementsPath = qmt::NameController::buildElementsPath(fileInfo.path(), false);
+}
+
+void FindComponentFromFilePath::visitMComponent(qmt::MComponent *component)
+{
+ if (component->getName() == m_elementName) {
+ QStringList elementPath;
+ const qmt::MObject *ancestor = component->getOwner();
+ while (ancestor) {
+ elementPath.prepend(ancestor->getName());
+ ancestor = ancestor->getOwner();
+ }
+ int i = elementPath.size() - 1;
+ int j = m_elementsPath.size() - 1;
+ while (i >= 0 && j >= 0 && elementPath.at(i) == m_elementsPath.at(j)) {
+ --i;
+ --j;
+ }
+ int pathLength = elementPath.size() - 1 - i;
+ if (pathLength > m_maxPathLength) {
+ m_maxPathLength = pathLength;
+ m_bestComponent = component;
+ }
+ }
+ visitMObject(component);
+}
+
+class UpdateIncludeDependenciesVisitor :
+ public qmt::MChildrenVisitor
+{
+ class Node
+ {
+ public:
+ Node() = default;
+ Node(const QString &filePath, const QStringList &elementPath)
+ : m_filePath(filePath),
+ m_elementPath(elementPath)
+ {
+ }
+
+ QString m_filePath;
+ QStringList m_elementPath;
+ };
+
+public:
+ void setModelController(qmt::ModelController *modelController);
+ void visitMComponent(qmt::MComponent *component);
+
+private:
+ bool haveMatchingStereotypes(const qmt::MObject *object1, const qmt::MObject *object2);
+ QStringList findFilePathOfComponent(const qmt::MComponent *component);
+ void collectElementPaths(const ProjectExplorer::FolderNode *folderNode, QMultiHash<QString,
+ Node> *filePathsMap);
+ qmt::MComponent *findComponentFromFilePath(const QString &filePath);
+ bool haveDependency(const qmt::MObject *source, const qmt::MObject *target,
+ bool inverted = false);
+ bool haveDependency(const qmt::MObject *source, const QList<qmt::MPackage *> &targets);
+
+private:
+ qmt::ModelController *m_modelController = 0;
+};
+
+void UpdateIncludeDependenciesVisitor::setModelController(qmt::ModelController *modelController)
+{
+ m_modelController = modelController;
+}
+
+void UpdateIncludeDependenciesVisitor::visitMComponent(qmt::MComponent *component)
+{
+ CppTools::CppModelManager *cppModelManager = CppTools::CppModelManager::instance();
+ CPlusPlus::Snapshot snapshot = cppModelManager->snapshot();
+
+ QStringList filePaths = findFilePathOfComponent(component);
+ foreach (const QString &filePath, filePaths) {
+ CPlusPlus::Document::Ptr document = snapshot.document(filePath);
+ if (document) {
+ foreach (const CPlusPlus::Document::Include &include, document->resolvedIncludes()) {
+ QString includeFilePath = include.resolvedFileName();
+ qmt::MComponent *includeComponent = findComponentFromFilePath(includeFilePath);
+ if (includeComponent && includeComponent != component) {
+ // add dependency between components
+ if (!haveDependency(component, includeComponent)) {
+ auto dependency = new qmt::MDependency;
+ dependency->setFlags(qmt::MElement::REVERSE_ENGINEERED);
+ dependency->setStereotypes(QStringList() << QStringLiteral("include"));
+ dependency->setDirection(qmt::MDependency::A_TO_B);
+ dependency->setSource(component->getUid());
+ dependency->setTarget(includeComponent->getUid());
+ m_modelController->addRelation(component, dependency);
+ }
+
+ // search ancestors sharing a common owner
+ QList<qmt::MPackage *> componentAncestors;
+ auto ancestor = dynamic_cast<qmt::MPackage *>(component->getOwner());
+ while (ancestor) {
+ componentAncestors.append(ancestor);
+ ancestor = dynamic_cast<qmt::MPackage *>(ancestor->getOwner());
+ }
+ QList<qmt::MPackage *> includeComponentAncestors;
+ ancestor = dynamic_cast<qmt::MPackage *>(includeComponent->getOwner());
+ while (ancestor) {
+ includeComponentAncestors.append(ancestor);
+ ancestor = dynamic_cast<qmt::MPackage *>(ancestor->getOwner());
+ }
+
+ int componentHighestAncestorIndex = componentAncestors.size() - 1;
+ int includeComponentHighestAncestorIndex = includeComponentAncestors.size() - 1;
+ QTC_ASSERT(componentAncestors.at(componentHighestAncestorIndex) == includeComponentAncestors.at(includeComponentHighestAncestorIndex), return);
+ while (componentHighestAncestorIndex > 0 && includeComponentHighestAncestorIndex > 0) {
+ if (componentAncestors.at(componentHighestAncestorIndex) != includeComponentAncestors.at(includeComponentHighestAncestorIndex))
+ break;
+ --componentHighestAncestorIndex;
+ --includeComponentHighestAncestorIndex;
+ }
+
+ // add dependency between parent packages with same stereotype
+ int index1 = 0;
+ int includeComponentLowestIndex = 0;
+ while (index1 <= componentHighestAncestorIndex
+ && includeComponentLowestIndex <= includeComponentHighestAncestorIndex) {
+ if (!componentAncestors.at(index1)->getStereotypes().isEmpty()) {
+ int index2 = includeComponentLowestIndex;
+ while (index2 <= includeComponentHighestAncestorIndex) {
+ if (haveMatchingStereotypes(componentAncestors.at(index1), includeComponentAncestors.at(index2))) {
+ if (!haveDependency(componentAncestors.at(index1), includeComponentAncestors.at(index2))) {
+ auto dependency = new qmt::MDependency;
+ dependency->setFlags(qmt::MElement::REVERSE_ENGINEERED);
+ dependency->setStereotypes(QStringList() << QStringLiteral("same stereotype"));
+ dependency->setDirection(qmt::MDependency::A_TO_B);
+ dependency->setSource(componentAncestors.at(index1)->getUid());
+ dependency->setTarget(includeComponentAncestors.at(index2)->getUid());
+ m_modelController->addRelation(componentAncestors.at(index1), dependency);
+ }
+ includeComponentLowestIndex = index2 + 1;
+ break;
+ }
+ ++index2;
+ }
+ }
+ ++index1;
+ }
+
+ // add dependency between topmost packages with common owner
+ if (componentAncestors.at(componentHighestAncestorIndex) != includeComponentAncestors.at(includeComponentHighestAncestorIndex)) {
+ if (!haveDependency(componentAncestors.at(componentHighestAncestorIndex), includeComponentAncestors)) {
+ auto dependency = new qmt::MDependency;
+ dependency->setFlags(qmt::MElement::REVERSE_ENGINEERED);
+ dependency->setStereotypes(QStringList() << QStringLiteral("ancestor"));
+ dependency->setDirection(qmt::MDependency::A_TO_B);
+ dependency->setSource(componentAncestors.at(componentHighestAncestorIndex)->getUid());
+ dependency->setTarget(includeComponentAncestors.at(includeComponentHighestAncestorIndex)->getUid());
+ m_modelController->addRelation(componentAncestors.at(componentHighestAncestorIndex), dependency);
+ }
+ }
+
+ // add dependency between parent packages
+ if (componentHighestAncestorIndex > 0 && includeComponentHighestAncestorIndex > 0) { // check for valid parents
+ if (componentAncestors.at(0) != includeComponentAncestors.at(0)) {
+ if (!haveDependency(componentAncestors.at(0), includeComponentAncestors)) {
+ auto dependency = new qmt::MDependency;
+ dependency->setFlags(qmt::MElement::REVERSE_ENGINEERED);
+ dependency->setStereotypes(QStringList() << QStringLiteral("parents"));
+ dependency->setDirection(qmt::MDependency::A_TO_B);
+ dependency->setSource(componentAncestors.at(0)->getUid());
+ dependency->setTarget(includeComponentAncestors.at(0)->getUid());
+ m_modelController->addRelation(componentAncestors.at(0), dependency);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ visitMObject(component);
+}
+
+bool UpdateIncludeDependenciesVisitor::haveMatchingStereotypes(const qmt::MObject *object1,
+ const qmt::MObject *object2)
+{
+ return !(object1->getStereotypes().toSet() & object2->getStereotypes().toSet()).isEmpty();
+}
+
+QStringList UpdateIncludeDependenciesVisitor::findFilePathOfComponent(const qmt::MComponent *component)
+{
+ QMultiHash<QString, Node> filePaths;
+ foreach (const ProjectExplorer::Project *project, ProjectExplorer::SessionManager::projects()) {
+ ProjectExplorer::ProjectNode *projectNode = project->rootProjectNode();
+ if (projectNode)
+ collectElementPaths(projectNode, &filePaths);
+ }
+ QStringList elementPath;
+ const qmt::MObject *ancestor = component->getOwner();
+ while (ancestor) {
+ elementPath.prepend(ancestor->getName());
+ ancestor = ancestor->getOwner();
+ }
+ QStringList bestFilePaths;
+ int maxPathLength = 1;
+ foreach (const Node &node, filePaths.values(component->getName())) {
+ int i = elementPath.size() - 1;
+ int j = node.m_elementPath.size() - 1;
+ while (i >= 0 && j >= 0 && elementPath.at(i) == node.m_elementPath.at(j)) {
+ --i;
+ --j;
+ }
+ int pathLength = elementPath.size() - 1 - i;
+ if (pathLength > maxPathLength)
+ bestFilePaths.clear();
+ if (pathLength >= maxPathLength) {
+ maxPathLength = pathLength;
+ bestFilePaths.append(node.m_filePath);
+ }
+ }
+ return bestFilePaths;
+}
+
+void UpdateIncludeDependenciesVisitor::collectElementPaths(const ProjectExplorer::FolderNode *folderNode,
+ QMultiHash<QString, Node> *filePathsMap)
+{
+ foreach (const ProjectExplorer::FileNode *fileNode, folderNode->fileNodes()) {
+ QString elementName = qmt::NameController::convertFileNameToElementName(fileNode->path().toString());
+ QFileInfo fileInfo(fileNode->path().toString());
+ QString nodePath = fileInfo.path();
+ QStringList elementsPath = qmt::NameController::buildElementsPath(nodePath, false);
+ filePathsMap->insertMulti(elementName, Node(fileNode->path().toString(), elementsPath));
+ }
+ foreach (const ProjectExplorer::FolderNode *subNode, folderNode->subFolderNodes())
+ collectElementPaths(subNode, filePathsMap);
+}
+
+qmt::MComponent *UpdateIncludeDependenciesVisitor::findComponentFromFilePath(const QString &filePath)
+{
+ FindComponentFromFilePath visitor;
+ visitor.setFilePath(filePath);
+ m_modelController->getRootPackage()->accept(&visitor);
+ return visitor.component();
+}
+
+bool UpdateIncludeDependenciesVisitor::haveDependency(const qmt::MObject *source,
+ const qmt::MObject *target, bool inverted)
+{
+ qmt::MDependency::Direction aToB = qmt::MDependency::A_TO_B;
+ qmt::MDependency::Direction bToA = qmt::MDependency::B_TO_A;
+ if (inverted) {
+ aToB = qmt::MDependency::B_TO_A;
+ bToA = qmt::MDependency::A_TO_B;
+ }
+ foreach (const qmt::Handle<qmt::MRelation> &handle, source->getRelations()) {
+ if (auto dependency = dynamic_cast<qmt::MDependency *>(handle.getTarget())) {
+ if (dependency->getSource() == source->getUid()
+ && dependency->getTarget() == target->getUid()
+ && (dependency->getDirection() == aToB
+ || dependency->getDirection() == qmt::MDependency::BIDIRECTIONAL)) {
+ return true;
+ }
+ if (dependency->getSource() == target->getUid()
+ && dependency->getTarget() == source->getUid()
+ && (dependency->getDirection() == bToA
+ || dependency->getDirection() == qmt::MDependency::BIDIRECTIONAL)) {
+ return true;
+ }
+ }
+ }
+ if (!inverted)
+ return haveDependency(target, source, true);
+ return false;
+}
+
+bool UpdateIncludeDependenciesVisitor::haveDependency(const qmt::MObject *source,
+ const QList<qmt::MPackage *> &targets)
+{
+ foreach (const qmt::MObject *target, targets) {
+ if (haveDependency(source, target))
+ return true;
+ }
+ return false;
+}
+
+class ComponentViewController::ComponentViewControllerPrivate {
+public:
+ PxNodeUtilities *pxnodeUtilities = 0;
+ qmt::DiagramSceneController *diagramSceneController = 0;
+};
+
+ComponentViewController::ComponentViewController(QObject *parent)
+ : QObject(parent),
+ d(new ComponentViewControllerPrivate)
+{
+}
+
+ComponentViewController::~ComponentViewController()
+{
+ delete d;
+}
+
+void ComponentViewController::setPxNodeUtilties(PxNodeUtilities *pxnodeUtilities)
+{
+ d->pxnodeUtilities = pxnodeUtilities;
+}
+
+void ComponentViewController::setDiagramSceneController(qmt::DiagramSceneController *diagramSceneController)
+{
+ d->diagramSceneController = diagramSceneController;
+}
+
+void ComponentViewController::createComponentModel(const ProjectExplorer::FolderNode *folderNode,
+ qmt::MDiagram *diagram,
+ const QString anchorFolder)
+{
+ foreach (const ProjectExplorer::FileNode *fileNode, folderNode->fileNodes()) {
+ QString componentName = qmt::NameController::convertFileNameToElementName(fileNode->path().toString());
+ qmt::MComponent *component = 0;
+ bool isSource = false;
+ CppTools::ProjectFile::Kind kind = CppTools::ProjectFile::classify(fileNode->path().toString());
+ switch (kind) {
+ case CppTools::ProjectFile::CHeader:
+ case CppTools::ProjectFile::CSource:
+ case CppTools::ProjectFile::CXXHeader:
+ case CppTools::ProjectFile::CXXSource:
+ case CppTools::ProjectFile::ObjCSource:
+ case CppTools::ProjectFile::ObjCHeader:
+ case CppTools::ProjectFile::ObjCXXSource:
+ case CppTools::ProjectFile::ObjCXXHeader:
+ case CppTools::ProjectFile::CudaSource:
+ case CppTools::ProjectFile::OpenCLSource:
+ isSource = true;
+ break;
+ case CppTools::ProjectFile::Unclassified:
+ isSource = false;
+ break;
+ }
+ if (isSource) {
+ component = new qmt::MComponent;
+ component->setFlags(qmt::MElement::REVERSE_ENGINEERED);
+ component->setName(componentName);
+ }
+ if (component) {
+ QStringList relativeElements = qmt::NameController::buildElementsPath(
+ d->pxnodeUtilities->calcRelativePath(fileNode, anchorFolder), false);
+ if (d->pxnodeUtilities->findSameObject(relativeElements, component)) {
+ delete component;
+ } else {
+ qmt::MPackage *requestedRootPackage = d->diagramSceneController->findSuitableParentPackage(0, diagram);
+ qmt::MPackage *bestParentPackage = d->pxnodeUtilities->createBestMatchingPackagePath(requestedRootPackage, relativeElements);
+ d->diagramSceneController->getModelController()->addObject(bestParentPackage, component);
+ }
+ }
+ }
+
+ foreach (const ProjectExplorer::FolderNode *subNode, folderNode->subFolderNodes())
+ createComponentModel(subNode, diagram, anchorFolder);
+}
+
+void ComponentViewController::updateIncludeDependencies(qmt::MPackage *rootPackage)
+{
+ UpdateIncludeDependenciesVisitor visitor;
+ visitor.setModelController(d->diagramSceneController->getModelController());
+ rootPackage->accept(&visitor);
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/componentviewcontroller.h b/src/plugins/modeleditor/componentviewcontroller.h
new file mode 100644
index 00000000000..4ac0eed2e23
--- /dev/null
+++ b/src/plugins/modeleditor/componentviewcontroller.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef COMPONENTVIEWCONTROLLER_H
+#define COMPONENTVIEWCONTROLLER_H
+
+#include <QObject>
+
+namespace ProjectExplorer { class FolderNode; }
+
+namespace qmt {
+class MPackage;
+class MDiagram;
+class DiagramSceneController;
+}
+
+namespace ModelEditor {
+namespace Internal {
+
+class PxNodeUtilities;
+
+class ComponentViewController :
+ public QObject
+{
+ Q_OBJECT
+ class ComponentViewControllerPrivate;
+
+public:
+ explicit ComponentViewController(QObject *parent = 0);
+ ~ComponentViewController();
+
+ void setPxNodeUtilties(PxNodeUtilities *pxnodeUtilities);
+ void setDiagramSceneController(qmt::DiagramSceneController *diagramSceneController);
+
+ void createComponentModel(const ProjectExplorer::FolderNode *folderNode,
+ qmt::MDiagram *diagram, const QString anchorFolder);
+ void updateIncludeDependencies(qmt::MPackage *rootPackage);
+
+private:
+ ComponentViewControllerPrivate *d;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // COMPONENTVIEWCONTROLLER_H
diff --git a/src/plugins/modeleditor/diagramdocument.cpp b/src/plugins/modeleditor/diagramdocument.cpp
new file mode 100644
index 00000000000..0e071c1c5d6
--- /dev/null
+++ b/src/plugins/modeleditor/diagramdocument.cpp
@@ -0,0 +1,210 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "diagramdocument.h"
+
+#include "modeleditor_constants.h"
+#include "modeleditor_plugin.h"
+#include "modelsmanager.h"
+#include "modeldocument.h"
+#include "extdocumentcontroller.h"
+
+#include "qmt/serializer/diagramreferenceserializer.h"
+#include "qmt/project_controller/projectcontroller.h"
+#include "qmt/project/project.h"
+#include "qmt/model_controller/modelcontroller.h"
+#include "qmt/model/mdiagram.h"
+#include "qmt/controller/namecontroller.h"
+
+#include <coreplugin/documentmanager.h>
+
+#include <utils/fileutils.h>
+
+#include <QFileInfo>
+
+namespace ModelEditor {
+namespace Internal {
+
+class DiagramDocument::DiagramDocumentPrivate {
+public:
+ ExtDocumentController *documentController = 0;
+ qmt::Uid diagramUid;
+};
+
+DiagramDocument::DiagramDocument(QObject *parent)
+ : Core::IDocument(parent),
+ d(new DiagramDocumentPrivate)
+{
+ setId(Constants::DIAGRAM_EDITOR_ID);
+ setMimeType(QLatin1String(Constants::MIME_TYPE_DIAGRAM_REFERENCE));
+}
+
+DiagramDocument::~DiagramDocument()
+{
+ if (d->documentController)
+ ModelEditorPlugin::modelsManager()->release(d->documentController, this);
+ delete d;
+}
+
+bool DiagramDocument::save(QString *errorString, const QString &name, bool autoSave)
+{
+ Q_UNUSED(autoSave);
+
+ if (!d->documentController) {
+ *errorString = tr("No model loaded. Cannot save diagram's model file.");
+ return false;
+ }
+
+ // "Save As" is not allowed"
+ if (!name.isEmpty() && name != filePath().toString()) {
+ *errorString = tr("Cannot save diagrams to file.");
+ return false;
+ }
+
+ ModelDocument *modelDocument = ModelEditorPlugin::modelsManager()->findModelDocument(d->documentController);
+ if (modelDocument) {
+ Core::DocumentManager::saveDocument(modelDocument);
+ } else {
+ try {
+ if (d->documentController->getProjectController()->isModified())
+ d->documentController->getProjectController()->save();
+ } catch (const qmt::Exception &ex) {
+ *errorString = ex.getErrorMsg();
+ return false;
+ }
+ }
+
+ onDiagramRenamed();
+
+ return true;
+}
+
+bool DiagramDocument::setContents(const QByteArray &contents)
+{
+ // load reference file
+ qmt::DiagramReferenceSerializer serializer;
+ qmt::DiagramReferenceSerializer::Reference reference = serializer.load(contents);
+
+ // this should never fail because the contents was generated from actual model and diagram
+ d->documentController = ModelEditorPlugin::modelsManager()->findOrLoadModel(reference._model_uid, this);
+ if (!d->documentController)
+ return false;
+ d->diagramUid = reference._diagram_uid;
+ qmt::MDiagram *diagram = d->documentController->getModelController()->findObject<qmt::MDiagram>(d->diagramUid);
+ if (!diagram)
+ return false;
+
+ connect(d->documentController, &qmt::DocumentController::changed, this, &IDocument::changed);
+
+ setTemporary(true);
+
+ // set document's file path to avoid asking for file path on saving document
+ // TODO encode model and diagram UIDs in path
+ // (allowing open from file name in DiagramEditor which is called
+ // if diagram shall be opened from navigation history)
+ QFileInfo fileInfo(d->documentController->getProjectController()->getProject()->getFileName());
+ QString filePath = fileInfo.path() + QStringLiteral("/")
+ + qmt::NameController::convertElementNameToBaseFileName(diagram->getName())
+ + QStringLiteral(".qdiagram");
+ setFilePath(Utils::FileName::fromString(filePath));
+
+ onDiagramRenamed();
+
+ emit contentSet();
+
+ return true;
+}
+
+bool DiagramDocument::isFileReadOnly() const
+{
+ ModelDocument *modelDocument = ModelEditorPlugin::modelsManager()->findModelDocument(d->documentController);
+ if (modelDocument)
+ return modelDocument->isFileReadOnly();
+ if (isTemporary())
+ return false;
+ return Core::IDocument::isFileReadOnly();
+}
+
+QString DiagramDocument::defaultPath() const
+{
+ return QLatin1String(".");
+}
+
+QString DiagramDocument::suggestedFileName() const
+{
+ return tr("diagram.qdiagram");
+}
+
+bool DiagramDocument::isModified() const
+{
+ return d->documentController ? d->documentController->getProjectController()->isModified() : false;
+}
+
+bool DiagramDocument::isSaveAsAllowed() const
+{
+ return false;
+}
+
+bool DiagramDocument::reload(QString *errorString, Core::IDocument::ReloadFlag flag,
+ Core::IDocument::ChangeType type)
+{
+ if (flag == FlagIgnore)
+ return true;
+ if (type == TypePermissions) {
+ emit changed();
+ return true;
+ }
+ *errorString = tr("Cannot reload diagram file.");
+ return false;
+}
+
+ExtDocumentController *DiagramDocument::documentController() const
+{
+ return d->documentController;
+}
+
+qmt::Uid DiagramDocument::diagramUid() const
+{
+ return d->diagramUid;
+}
+
+void DiagramDocument::onDiagramRenamed()
+{
+ qmt::MDiagram *diagram = d->documentController->getModelController()->findObject<qmt::MDiagram>(d->diagramUid);
+ if (diagram) {
+ QFileInfo fileInfo(d->documentController->getProjectController()->getProject()->getFileName());
+ setPreferredDisplayName(tr("%1 [%2]").arg(diagram->getName()).arg(fileInfo.fileName()));
+ } else {
+ setPreferredDisplayName(QString());
+ }
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/diagramdocument.h b/src/plugins/modeleditor/diagramdocument.h
new file mode 100644
index 00000000000..503c4f070b6
--- /dev/null
+++ b/src/plugins/modeleditor/diagramdocument.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef DIAGRAMDOCUMENT_H
+#define DIAGRAMDOCUMENT_H
+
+#include <coreplugin/idocument.h>
+#include "documentinterface.h"
+
+namespace ModelEditor {
+namespace Internal {
+
+class DiagramDocument :
+ public Core::IDocument,
+ public DocumentInterface
+{
+ Q_OBJECT
+ class DiagramDocumentPrivate;
+
+public:
+ explicit DiagramDocument(QObject *parent = 0);
+ ~DiagramDocument();
+
+signals:
+ void contentSet();
+
+public:
+ bool save(QString *errorString, const QString &name, bool autoSave) override;
+ bool setContents(const QByteArray &contents) override;
+ bool isFileReadOnly() const override;
+ QString defaultPath() const override;
+ QString suggestedFileName() const override;
+ bool isModified() const override;
+ bool isSaveAsAllowed() const override;
+ bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override;
+
+ ExtDocumentController *documentController() const override;
+ qmt::Uid diagramUid() const override;
+
+ void onDiagramRenamed();
+
+private:
+ DiagramDocumentPrivate *d;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // DIAGRAMDOCUMENT_H
diff --git a/src/plugins/modeleditor/diagrameditor.cpp b/src/plugins/modeleditor/diagrameditor.cpp
new file mode 100644
index 00000000000..9a70b833d3c
--- /dev/null
+++ b/src/plugins/modeleditor/diagrameditor.cpp
@@ -0,0 +1,89 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "diagrameditor.h"
+
+#include "modeleditor_constants.h"
+#include "diagramdocument.h"
+#include "extdocumentcontroller.h"
+
+#include "qmt/model/mdiagram.h"
+#include "qmt/model_controller/modelcontroller.h"
+#include "qmt/project/project.h"
+#include "qmt/project_controller/projectcontroller.h"
+
+#include <utils/qtcassert.h>
+
+#include <QFileInfo>
+
+namespace ModelEditor {
+namespace Internal {
+
+class DiagramEditor::DiagramEditorPrivate
+{
+public:
+ DiagramDocument *document = 0;
+};
+
+DiagramEditor::DiagramEditor(UiController *uiController, ActionHandler *actionHandler,
+ QWidget *parent)
+ : AbstractEditor(uiController, actionHandler, parent),
+ d(new DiagramEditorPrivate)
+{
+ setContext(Core::Context(Constants::DIAGRAM_EDITOR_ID));
+ d->document = new DiagramDocument(this);
+ connect(d->document, &DiagramDocument::contentSet, this, &DiagramEditor::onContentSet);
+ init(parent);
+}
+
+DiagramEditor::~DiagramEditor()
+{
+ delete d;
+}
+
+Core::IDocument *DiagramEditor::document()
+{
+ return d->document;
+}
+
+void DiagramEditor::onContentSet()
+{
+ setDocument(d->document);
+
+ // open diagram
+ qmt::MDiagram *diagram = d->document->documentController()->getModelController()->findObject<qmt::MDiagram>(d->document->diagramUid());
+ QTC_ASSERT(diagram, return);
+ showDiagram(diagram);
+
+ expandModelTreeToDepth(0);
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/diagrameditor.h b/src/plugins/modeleditor/diagrameditor.h
new file mode 100644
index 00000000000..71a9a721984
--- /dev/null
+++ b/src/plugins/modeleditor/diagrameditor.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef DIAGRAMEDITOR_H
+#define DIAGRAMEDITOR_H
+
+#include "abstracteditor.h"
+
+namespace ModelEditor {
+namespace Internal {
+
+class DiagramEditor :
+ public AbstractEditor
+{
+ Q_OBJECT
+ class DiagramEditorPrivate;
+
+public:
+ explicit DiagramEditor(UiController *uiController, ActionHandler *actionHandler,
+ QWidget *parent = 0);
+ ~DiagramEditor();
+
+ Core::IDocument *document() override;
+
+private slots:
+ void onContentSet();
+
+private:
+ DiagramEditorPrivate *d;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // DIAGRAMEDITOR_H
diff --git a/src/plugins/modeleditor/diagrameditorfactory.cpp b/src/plugins/modeleditor/diagrameditorfactory.cpp
new file mode 100644
index 00000000000..0c9cbe1e345
--- /dev/null
+++ b/src/plugins/modeleditor/diagrameditorfactory.cpp
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "diagrameditorfactory.h"
+
+#include "modeleditor_constants.h"
+#include "actionhandler.h"
+#include "diagrameditor.h"
+
+#include <QApplication>
+
+namespace ModelEditor {
+namespace Internal {
+
+class DiagramEditorFactory::DiagramEditorFactoryPrivate
+{
+public:
+ UiController *uiController = 0;
+ ActionHandler *actionHandler = 0;
+};
+
+DiagramEditorFactory::DiagramEditorFactory(UiController *uiController, QObject *parent)
+ : Core::IEditorFactory(parent),
+ d(new DiagramEditorFactoryPrivate)
+{
+ setId(Constants::DIAGRAM_EDITOR_ID);
+ setDisplayName(qApp->translate("OpenWith::Editors", Constants::DIAGRAM_EDITOR_DISPLAY_NAME));
+ addMimeType(Constants::MIME_TYPE_DIAGRAM_REFERENCE);
+ d->uiController = uiController;
+ d->actionHandler = new ActionHandler(Core::Context(Constants::DIAGRAM_EDITOR_ID), this);
+}
+
+DiagramEditorFactory::~DiagramEditorFactory()
+{
+ delete d;
+}
+
+Core::IEditor *DiagramEditorFactory::createEditor()
+{
+ return new DiagramEditor(d->uiController, d->actionHandler);
+}
+
+void DiagramEditorFactory::extensionsInitialized()
+{
+ d->actionHandler->createActions();
+ d->actionHandler->createEditPropertiesShortcut(
+ Constants::SHORTCUT_DIAGRAM_EDITOR_EDIT_PROPERTIES);
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/diagrameditorfactory.h b/src/plugins/modeleditor/diagrameditorfactory.h
new file mode 100644
index 00000000000..4b650897e03
--- /dev/null
+++ b/src/plugins/modeleditor/diagrameditorfactory.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef DIAGRAMEDITORFACTORY_H
+#define DIAGRAMEDITORFACTORY_H
+
+#include <coreplugin/editormanager/ieditorfactory.h>
+
+namespace ModelEditor {
+namespace Internal {
+
+class UiController;
+
+class DiagramEditorFactory :
+ public Core::IEditorFactory
+{
+ Q_OBJECT
+ class DiagramEditorFactoryPrivate;
+
+public:
+ explicit DiagramEditorFactory(UiController *uiController, QObject *parent = 0);
+ ~DiagramEditorFactory();
+
+ Core::IEditor *createEditor() override;
+
+ void extensionsInitialized();
+
+private:
+ DiagramEditorFactoryPrivate *d;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // DIAGRAMEDITORFACTORY_H
diff --git a/src/plugins/modeleditor/diagramsviewmanager.cpp b/src/plugins/modeleditor/diagramsviewmanager.cpp
new file mode 100644
index 00000000000..f844ef2006d
--- /dev/null
+++ b/src/plugins/modeleditor/diagramsviewmanager.cpp
@@ -0,0 +1,87 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "diagramsviewmanager.h"
+
+#include "abstracteditor.h"
+
+#include <coreplugin/editormanager/editormanager.h>
+#include <utils/qtcassert.h>
+
+#include <QDebug>
+
+namespace ModelEditor {
+namespace Internal {
+
+// TODO eliminate this class - realize interface in class ModelsManager.
+
+DiagramsViewManager::DiagramsViewManager(QObject *parent)
+ : QObject(parent)
+{
+ // TODO connect to EditorManager if active editor changed;
+ // then emit currentDiagramChanged eventually
+}
+
+qmt::MDiagram *DiagramsViewManager::getCurrentDiagram() const
+{
+ // TODO currentEditor() is not good enough in case of split editors
+ // (drag&drop can be done in non-current editor but expects current diagram != 0)
+ Core::IEditor *editor = Core::EditorManager::currentEditor();
+ auto abstractEditor = dynamic_cast<AbstractEditor *>(editor);
+ if (!abstractEditor)
+ return 0;
+ return abstractEditor->editorDiagram();
+}
+
+void DiagramsViewManager::openDiagram(qmt::MDiagram *diagram)
+{
+ emit openEditor(diagram);
+}
+
+void DiagramsViewManager::closeDiagram(const qmt::MDiagram *diagram)
+{
+ emit closeEditor(diagram);
+}
+
+void DiagramsViewManager::closeAllDiagrams()
+{
+ // should never be called in this realization
+ QTC_CHECK(false);
+}
+
+void DiagramsViewManager::onDiagramRenamed(const qmt::MDiagram *diagram)
+{
+ emit diagramRenamed(diagram);
+}
+
+} // namespace Internal
+} // namespace ModelEditor
+
+
diff --git a/src/plugins/modeleditor/diagramsviewmanager.h b/src/plugins/modeleditor/diagramsviewmanager.h
new file mode 100644
index 00000000000..69235d45956
--- /dev/null
+++ b/src/plugins/modeleditor/diagramsviewmanager.h
@@ -0,0 +1,80 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef DIAGRAMSVIEWMANAGER_H
+#define DIAGRAMSVIEWMANAGER_H
+
+#include <QObject>
+#include "qmt/diagram_ui/diagramsviewinterface.h"
+
+#include <QHash>
+
+namespace qmt {
+class Uid;
+class DiagramView;
+class MDiagram;
+}
+
+namespace ModelEditor {
+namespace Internal {
+
+class DiagramsViewManager :
+ public QObject,
+ public qmt::DiagramsViewInterface
+{
+ Q_OBJECT
+
+public:
+ explicit DiagramsViewManager(QObject *parent = 0);
+ ~DiagramsViewManager() = default;
+
+signals:
+ void currentDiagramChanged(const qmt::MDiagram *diagram);
+
+ // This signal is never emitted but exists for API compatibility to other realizations
+ // of qmt::DiagramsViewInterface. The signal is not needed in the context of ModelEditor plugin
+ void someDiagramOpened(bool);
+
+ void openEditor(const qmt::MDiagram *diagram);
+ void closeEditor(const qmt::MDiagram *diagram);
+ void diagramRenamed(const qmt::MDiagram *diagram);
+
+public:
+ qmt::MDiagram *getCurrentDiagram() const override;
+ void openDiagram(qmt::MDiagram *diagram) override;
+ void closeDiagram(const qmt::MDiagram *diagram) override;
+ void closeAllDiagrams() override;
+ void onDiagramRenamed(const qmt::MDiagram *diagram) override;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // DIAGRAMSVIEWMANAGER_H
diff --git a/src/plugins/modeleditor/documentinterface.h b/src/plugins/modeleditor/documentinterface.h
new file mode 100644
index 00000000000..efa5770d5f4
--- /dev/null
+++ b/src/plugins/modeleditor/documentinterface.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef DOCUMENTINTERFACE_H
+#define DOCUMENTINTERFACE_H
+
+#include "qmt/infrastructure/uid.h"
+
+namespace ModelEditor {
+namespace Internal {
+
+class ExtDocumentController;
+
+class DocumentInterface {
+public:
+ virtual ~DocumentInterface() { }
+ virtual ExtDocumentController *documentController() const = 0;
+ virtual qmt::Uid diagramUid() const = 0;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // DOCUMENTINTERFACE_H
diff --git a/src/plugins/modeleditor/dragtool.cpp b/src/plugins/modeleditor/dragtool.cpp
new file mode 100644
index 00000000000..7b39b9f09a8
--- /dev/null
+++ b/src/plugins/modeleditor/dragtool.cpp
@@ -0,0 +1,182 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "dragtool.h"
+
+#include "qmt/diagram_ui/diagram_mime_types.h"
+
+#include <QPainter>
+#include <QCursor>
+#include <QDrag>
+#include <QMouseEvent>
+#include <QMimeData>
+
+namespace ModelEditor {
+namespace Internal {
+
+class DragTool::DragToolPrivate {
+public:
+ QIcon icon;
+ QSize iconSize;
+ QString title;
+ QString newElementId;
+ QString stereotype;
+ bool disableFrame = false;
+ bool framePainted = false;
+};
+
+DragTool::DragTool(const QIcon &icon, const QString &title, const QString &newElementId,
+ const QString &stereotype, QWidget *parent)
+ : QWidget(parent),
+ d(new DragToolPrivate)
+{
+ d->icon = icon;
+ d->iconSize = QSize(32, 32);
+ d->title = title;
+ d->newElementId = newElementId;
+ d->stereotype = stereotype;
+ QMargins margins = contentsMargins();
+ if (margins.top() < 3)
+ margins.setTop(3);
+ if (margins.bottom() < 3)
+ margins.setBottom(3);
+ if (margins.left() < 3)
+ margins.setLeft(3);
+ if (margins.right() < 3)
+ margins.setRight(3);
+ setContentsMargins(margins);
+}
+
+DragTool::~DragTool()
+{
+ delete d;
+}
+
+QSize DragTool::sizeHint() const
+{
+ int width = 0;
+ int height = 0;
+ if (d->iconSize.width() > width)
+ width = d->iconSize.width();
+ height += d->iconSize.height();
+ QRect textRect = fontMetrics().boundingRect(QRect(), Qt::AlignLeft | Qt::TextSingleLine, d->title);
+ if (textRect.width() > width)
+ width = textRect.width();
+ height += textRect.height();
+ QMargins margins = contentsMargins();
+ width += margins.left() + margins.right();
+ height += margins.top() + margins.bottom();
+ return QSize(width, height);
+}
+
+void DragTool::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event);
+ QMargins margins = contentsMargins();
+ QPixmap pixmap = d->icon.pixmap(d->iconSize, isEnabled() ? QIcon::Normal : QIcon::Disabled, QIcon::Off);
+ QPainter painter(this);
+ QRect targetRect((width() - pixmap.width()) / 2,
+ margins.top() + (d->iconSize.height() - pixmap.height()) / 2,
+ pixmap.width(),
+ pixmap.height());
+ QRect sourceRect(0, 0, pixmap.width(), pixmap.height());
+ painter.drawPixmap(targetRect, pixmap, sourceRect);
+
+ QRect textRect = painter.boundingRect(QRect(), Qt::AlignLeft | Qt::TextSingleLine, d->title);
+ QRect boundingRect(0, d->iconSize.height(), width(), textRect.height());
+ painter.drawText(boundingRect, Qt::AlignHCenter | Qt::TextSingleLine, d->title);
+
+ // draw a weak frame if mouse is inside widget
+ if (!d->disableFrame && rect().contains(QWidget::mapFromGlobal(QCursor::pos()))) {
+ QRect rect(0, 0, width() - 1, height() - 1);
+ QPen pen = painter.pen();
+ pen.setStyle(Qt::DotLine);
+ painter.setPen(pen);
+ painter.drawRect(rect);
+ d->framePainted = true;
+ } else {
+ d->framePainted = false;
+ }
+}
+
+void DragTool::enterEvent(QEvent *event)
+{
+ Q_UNUSED(event);
+ update();
+}
+
+void DragTool::leaveEvent(QEvent *event)
+{
+ Q_UNUSED(event);
+ update();
+}
+
+void DragTool::mousePressEvent(QMouseEvent *event)
+{
+ if (event->button() == Qt::LeftButton) {
+ const QMargins margins = contentsMargins();
+ const QRect iconRect((width() - d->iconSize.width()) / 2, margins.top(),
+ d->iconSize.width(), d->iconSize.height());
+ if (iconRect.contains(event->pos())) {
+ auto drag = new QDrag(this);
+ auto mimeData = new QMimeData;
+ QByteArray data;
+ QDataStream dataStream(&data, QIODevice::WriteOnly);
+ dataStream << d->newElementId << d->title << d->stereotype;
+ mimeData->setData(QLatin1String(qmt::MIME_TYPE_NEW_MODEL_ELEMENTS), data);
+ drag->setMimeData(mimeData);
+
+ QPixmap pixmap = d->icon.pixmap(d->iconSize, QIcon::Normal, QIcon::Off);
+ QPainter painter(&pixmap);
+ painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
+ painter.fillRect(pixmap.rect(), QColor(0, 0, 0, 96));
+ drag->setPixmap(pixmap);
+ drag->setHotSpot(QPoint(drag->pixmap().width() / 2, drag->pixmap().height() / 2));
+
+ d->disableFrame = true;
+ update();
+ Qt::DropAction dropAction = drag->exec();
+ Q_UNUSED(dropAction);
+ d->disableFrame = false;
+ update();
+ }
+ }
+}
+
+void DragTool::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_UNUSED(event);
+ const bool containsMouse = rect().contains(QWidget::mapFromGlobal(QCursor::pos()));
+ if ((d->framePainted && !containsMouse) || (!d->framePainted && containsMouse))
+ update();
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/dragtool.h b/src/plugins/modeleditor/dragtool.h
new file mode 100644
index 00000000000..be3a16f4e67
--- /dev/null
+++ b/src/plugins/modeleditor/dragtool.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef DRAGTOOL_H
+#define DRAGTOOL_H
+
+#include <QWidget>
+#include <QIcon>
+
+namespace ModelEditor {
+namespace Internal {
+
+class DragTool :
+ public QWidget
+{
+ Q_OBJECT
+ class DragToolPrivate;
+
+public:
+ DragTool(const QIcon &icon, const QString &title, const QString &newElementId,
+ const QString &stereotype, QWidget *parent = 0);
+ ~DragTool();
+
+ QSize sizeHint() const override;
+
+protected:
+ void paintEvent(QPaintEvent *event) override;
+ void enterEvent(QEvent *event) override;
+ void leaveEvent(QEvent *event) override;
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
+
+private:
+ DragToolPrivate *d;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // DRAGTOOL_H
diff --git a/src/plugins/modeleditor/editordiagramview.cpp b/src/plugins/modeleditor/editordiagramview.cpp
new file mode 100644
index 00000000000..b2e0d00446f
--- /dev/null
+++ b/src/plugins/modeleditor/editordiagramview.cpp
@@ -0,0 +1,84 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "editordiagramview.h"
+
+#include "pxnodecontroller.h"
+
+#include "qmt/diagram_scene/diagramscenemodel.h"
+#include "qmt/tasks/diagramscenecontroller.h"
+
+#include <projectexplorer/projectnodes.h>
+#include <utils/dropsupport.h>
+
+namespace ModelEditor {
+namespace Internal {
+
+class EditorDiagramView::EditorDiagramViewPrivate {
+public:
+ PxNodeController *pxNodeController = 0;
+};
+
+EditorDiagramView::EditorDiagramView(QWidget *parent)
+ : qmt::DiagramView(parent),
+ d(new EditorDiagramViewPrivate)
+{
+ auto droputils = new Utils::DropSupport(
+ this,
+ [this](QDropEvent *event, Utils::DropSupport *dropSupport)
+ -> bool { return dropSupport->isValueDrop(event); });
+ // TODO use slot instead of lambda, lambda is to long and complex
+ connect(droputils, &Utils::DropSupport::valuesDropped,
+ this,
+ [this](const QList<QVariant> &values, const QPoint &pos) {
+ foreach (const QVariant &value, values) {
+ if (value.canConvert<ProjectExplorer::Node *>()) {
+ auto node = value.value<ProjectExplorer::Node *>();
+ QPointF scenePos = mapToScene(pos);
+ d->pxNodeController->addExplorerNode(
+ node, getDiagramSceneModel()->findTopmostElement(scenePos),
+ scenePos, getDiagramSceneModel()->getDiagram());
+ }
+ }
+ });
+}
+
+EditorDiagramView::~EditorDiagramView()
+{
+ delete d;
+}
+
+void EditorDiagramView::setPxNodeController(PxNodeController *pxNodeController)
+{
+ d->pxNodeController = pxNodeController;
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/editordiagramview.h b/src/plugins/modeleditor/editordiagramview.h
new file mode 100644
index 00000000000..5968556cf2a
--- /dev/null
+++ b/src/plugins/modeleditor/editordiagramview.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef EDITORDIAGRAMVIEW_H
+#define EDITORDIAGRAMVIEW_H
+
+#include "qmt/diagram_widgets_ui/diagramview.h"
+
+namespace ModelEditor {
+namespace Internal {
+
+class PxNodeController;
+
+class EditorDiagramView :
+ public qmt::DiagramView
+{
+ Q_OBJECT
+ class EditorDiagramViewPrivate;
+
+public:
+ explicit EditorDiagramView(QWidget *parent = 0);
+ ~EditorDiagramView();
+
+ void setPxNodeController(PxNodeController *pxNodeController);
+
+private:
+ EditorDiagramViewPrivate *d;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // EDITORDIAGRAMVIEW_H
diff --git a/src/plugins/modeleditor/elementtasks.cpp b/src/plugins/modeleditor/elementtasks.cpp
new file mode 100644
index 00000000000..8f700c9d88d
--- /dev/null
+++ b/src/plugins/modeleditor/elementtasks.cpp
@@ -0,0 +1,355 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "elementtasks.h"
+
+#include "modelsmanager.h"
+#include "openelementvisitor.h"
+#include "modeleditor_plugin.h"
+
+#include "qmt/diagram/delement.h"
+#include "qmt/document_controller/documentcontroller.h"
+#include "qmt/model/melement.h"
+#include "qmt/model/mclass.h"
+#include "qmt/model/mdiagram.h"
+#include "qmt/model/mcanvasdiagram.h"
+#include "qmt/model/mpackage.h"
+#include "qmt/model_controller/modelcontroller.h"
+#include "qmt/tasks/finddiagramvisitor.h"
+#include "qmt/project_controller/projectcontroller.h"
+#include "qmt/project/project.h"
+
+#include <extensionsystem/pluginmanager.h>
+#include <cpptools/cppclassesfilter.h>
+#include <cpptools/indexitem.h>
+#include <cpptools/searchsymbols.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/locator/ilocatorfilter.h>
+#include <utils/qtcassert.h>
+
+namespace ModelEditor {
+namespace Internal {
+
+class ElementTasks::ElementTasksPrivate {
+public:
+ qmt::DocumentController *documentController = 0;
+};
+
+ElementTasks::ElementTasks()
+ : d(new ElementTasksPrivate)
+{
+}
+
+ElementTasks::~ElementTasks()
+{
+ delete d;
+}
+
+void ElementTasks::setDocumentController(qmt::DocumentController *documentController)
+{
+ d->documentController = documentController;
+}
+
+void ElementTasks::openElement(const qmt::MElement *element)
+{
+ OpenModelElementVisitor visitor;
+ visitor.setElementTasks(this);
+ element->accept(&visitor);
+}
+
+void ElementTasks::openElement(const qmt::DElement *element, const qmt::MDiagram *diagram)
+{
+ Q_UNUSED(diagram);
+
+ OpenDiagramElementVisitor visitor;
+ visitor.setModelController(d->documentController->getModelController());
+ visitor.setElementTasks(this);
+ element->accept(&visitor);
+}
+
+bool ElementTasks::hasClassDefinition(const qmt::MElement *element) const
+{
+ if (auto klass = dynamic_cast<const qmt::MClass *>(element)) {
+ QString qualifiedClassName = klass->getNamespace().isEmpty()
+ ? klass->getName()
+ : klass->getNamespace() + QStringLiteral("::") + klass->getName();
+
+ CppTools::CppClassesFilter *classesFilter = ExtensionSystem::PluginManager::getObject<CppTools::CppClassesFilter>();
+ if (!classesFilter)
+ return false;
+
+ QFutureInterface<Core::LocatorFilterEntry> dummyInterface;
+ QList<Core::LocatorFilterEntry> matches = classesFilter->matchesFor(dummyInterface,
+ qualifiedClassName);
+ foreach (const Core::LocatorFilterEntry &entry, matches) {
+ CppTools::IndexItem::Ptr info = qvariant_cast<CppTools::IndexItem::Ptr>(entry.internalData);
+ if (info->scopedSymbolName() != qualifiedClassName)
+ continue;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ElementTasks::hasClassDefinition(const qmt::DElement *element,
+ const qmt::MDiagram *diagram) const
+{
+ Q_UNUSED(diagram);
+
+ qmt::MElement *melement = d->documentController->getModelController()->findElement(
+ element->getModelUid());
+ if (!melement)
+ return false;
+ return hasClassDefinition(melement);
+}
+
+void ElementTasks::openClassDefinition(const qmt::MElement *element)
+{
+ if (auto klass = dynamic_cast<const qmt::MClass *>(element)) {
+ QString qualifiedClassName = klass->getNamespace().isEmpty()
+ ? klass->getName()
+ : klass->getNamespace() + QStringLiteral("::") + klass->getName();
+
+ CppTools::CppClassesFilter *classesFilter = ExtensionSystem::PluginManager::getObject<CppTools::CppClassesFilter>();
+ if (!classesFilter)
+ return;
+
+ QFutureInterface<Core::LocatorFilterEntry> dummyInterface;
+ QList<Core::LocatorFilterEntry> matches = classesFilter->matchesFor(dummyInterface, qualifiedClassName);
+ foreach (const Core::LocatorFilterEntry &entry, matches) {
+ CppTools::IndexItem::Ptr info = qvariant_cast<CppTools::IndexItem::Ptr>(entry.internalData);
+ if (info->scopedSymbolName() != qualifiedClassName)
+ continue;
+ if (Core::EditorManager::instance()->openEditorAt(info->fileName(), info->line(), info->column()))
+ return;
+ }
+ }
+}
+
+void ElementTasks::openClassDefinition(const qmt::DElement *element, const qmt::MDiagram *diagram)
+{
+ Q_UNUSED(diagram);
+
+ qmt::MElement *melement = d->documentController->getModelController()->findElement(element->getModelUid());
+ if (!melement)
+ return;
+ openClassDefinition(melement);
+}
+
+bool ElementTasks::hasHeaderFile(const qmt::MElement *element) const
+{
+ // TODO implement
+ Q_UNUSED(element);
+ return false;
+}
+
+bool ElementTasks::hasHeaderFile(const qmt::DElement *element, const qmt::MDiagram *diagram) const
+{
+ Q_UNUSED(diagram);
+
+ qmt::MElement *melement = d->documentController->getModelController()->findElement(element->getModelUid());
+ if (!melement)
+ return false;
+ return hasHeaderFile(melement);
+}
+
+bool ElementTasks::hasSourceFile(const qmt::MElement *element) const
+{
+ // TODO implement
+ Q_UNUSED(element);
+ return false;
+}
+
+bool ElementTasks::hasSourceFile(const qmt::DElement *element, const qmt::MDiagram *diagram) const
+{
+ Q_UNUSED(diagram);
+
+ qmt::MElement *melement = d->documentController->getModelController()->findElement(element->getModelUid());
+ if (!melement)
+ return false;
+ return hasSourceFile(melement);
+}
+
+void ElementTasks::openHeaderFile(const qmt::MElement *element)
+{
+ // TODO implement
+ Q_UNUSED(element);
+}
+
+void ElementTasks::openHeaderFile(const qmt::DElement *element, const qmt::MDiagram *diagram)
+{
+ Q_UNUSED(diagram);
+
+ qmt::MElement *melement = d->documentController->getModelController()->findElement(element->getModelUid());
+ if (!melement)
+ return;
+ openHeaderFile(melement);
+}
+
+void ElementTasks::openSourceFile(const qmt::MElement *element)
+{
+ // TODO implement
+ Q_UNUSED(element);
+}
+
+void ElementTasks::openSourceFile(const qmt::DElement *element, const qmt::MDiagram *diagram)
+{
+ Q_UNUSED(diagram);
+
+ qmt::MElement *melement = d->documentController->getModelController()->findElement(element->getModelUid());
+ if (!melement)
+ return;
+ openSourceFile(melement);
+}
+
+bool ElementTasks::hasFolder(const qmt::MElement *element) const
+{
+ // TODO implement
+ Q_UNUSED(element);
+ return false;
+}
+
+bool ElementTasks::hasFolder(const qmt::DElement *element, const qmt::MDiagram *diagram) const
+{
+ Q_UNUSED(diagram);
+
+ qmt::MElement *melement = d->documentController->getModelController()->findElement(element->getModelUid());
+ if (!melement)
+ return false;
+ return hasFolder(melement);
+}
+
+void ElementTasks::showFolder(const qmt::MElement *element)
+{
+ // TODO implement
+ Q_UNUSED(element);
+}
+
+void ElementTasks::showFolder(const qmt::DElement *element, const qmt::MDiagram *diagram)
+{
+ Q_UNUSED(diagram);
+
+ qmt::MElement *melement = d->documentController->getModelController()->findElement(element->getModelUid());
+ if (!melement)
+ return;
+ showFolder(melement);
+}
+
+bool ElementTasks::hasDiagram(const qmt::MElement *element) const
+{
+ qmt::FindDiagramVisitor visitor;
+ element->accept(&visitor);
+ const qmt::MDiagram *diagram = visitor.getDiagram();
+ return diagram != 0;
+}
+
+bool ElementTasks::hasDiagram(const qmt::DElement *element, const qmt::MDiagram *diagram) const
+{
+ Q_UNUSED(diagram);
+
+ qmt::MElement *melement = d->documentController->getModelController()->findElement(element->getModelUid());
+ if (!melement)
+ return false;
+ return hasDiagram(melement);
+}
+
+void ElementTasks::openDiagram(const qmt::MElement *element)
+{
+ qmt::FindDiagramVisitor visitor;
+ element->accept(&visitor);
+ const qmt::MDiagram *diagram = visitor.getDiagram();
+ if (diagram) {
+ ModelEditorPlugin::modelsManager()->openDiagram(
+ d->documentController->getProjectController()->getProject()->getUid(),
+ diagram->getUid());
+ }
+}
+
+void ElementTasks::openDiagram(const qmt::DElement *element, const qmt::MDiagram *diagram)
+{
+ Q_UNUSED(diagram);
+
+ qmt::MElement *melement = d->documentController->getModelController()->findElement(element->getModelUid());
+ if (!melement)
+ return;
+ openDiagram(melement);
+}
+
+bool ElementTasks::mayCreateDiagram(const qmt::MElement *element) const
+{
+ return dynamic_cast<const qmt::MPackage *>(element) != 0;
+}
+
+bool ElementTasks::mayCreateDiagram(const qmt::DElement *element,
+ const qmt::MDiagram *diagram) const
+{
+ Q_UNUSED(diagram);
+
+ qmt::MElement *melement = d->documentController->getModelController()->findElement(element->getModelUid());
+ if (!melement)
+ return false;
+ return mayCreateDiagram(melement);
+}
+
+void ElementTasks::createAndOpenDiagram(const qmt::MElement *element)
+{
+ if (auto package = dynamic_cast<const qmt::MPackage *>(element)) {
+ qmt::FindDiagramVisitor visitor;
+ element->accept(&visitor);
+ const qmt::MDiagram *diagram = visitor.getDiagram();
+ if (diagram) {
+ ModelEditorPlugin::modelsManager()->openDiagram(
+ d->documentController->getProjectController()->getProject()->getUid(),
+ diagram->getUid());
+ } else {
+ auto newDiagram = new qmt::MCanvasDiagram();
+ newDiagram->setName(package->getName());
+ qmt::MPackage *parentPackage = d->documentController->getModelController()->findObject<qmt::MPackage>(package->getUid());
+ QTC_ASSERT(parentPackage, delete newDiagram; return);
+ d->documentController->getModelController()->addObject(parentPackage, newDiagram);
+ ModelEditorPlugin::modelsManager()->openDiagram(
+ d->documentController->getProjectController()->getProject()->getUid(),
+ newDiagram->getUid());
+ }
+ }
+}
+
+void ElementTasks::createAndOpenDiagram(const qmt::DElement *element, const qmt::MDiagram *diagram)
+{
+ Q_UNUSED(diagram);
+
+ qmt::MElement *melement = d->documentController->getModelController()->findElement(element->getModelUid());
+ if (!melement)
+ return;
+ createAndOpenDiagram(melement);
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/elementtasks.h b/src/plugins/modeleditor/elementtasks.h
new file mode 100644
index 00000000000..a17e0f5c41d
--- /dev/null
+++ b/src/plugins/modeleditor/elementtasks.h
@@ -0,0 +1,93 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef ELEMENTTASKS_H
+#define ELEMENTTASKS_H
+
+#include "qmt/tasks/ielementtasks.h"
+
+namespace qmt { class DocumentController; }
+
+namespace ModelEditor {
+namespace Internal {
+
+class ElementTasks :
+ public qmt::IElementTasks
+{
+ class ElementTasksPrivate;
+
+public:
+ ElementTasks();
+ ~ElementTasks();
+
+ void setDocumentController(qmt::DocumentController *documentController);
+
+ void openElement(const qmt::MElement *element) override;
+ void openElement(const qmt::DElement *element, const qmt::MDiagram *diagram) override;
+
+ bool hasClassDefinition(const qmt::MElement *element) const override;
+ bool hasClassDefinition(const qmt::DElement *element,
+ const qmt::MDiagram *diagram) const override;
+ void openClassDefinition(const qmt::MElement *element) override;
+ void openClassDefinition(const qmt::DElement *element, const qmt::MDiagram *diagram) override;
+
+ bool hasHeaderFile(const qmt::MElement *element) const override;
+ bool hasHeaderFile(const qmt::DElement *element, const qmt::MDiagram *diagram) const override;
+ bool hasSourceFile(const qmt::MElement *element) const override;
+ bool hasSourceFile(const qmt::DElement *element, const qmt::MDiagram *diagram) const override;
+ void openHeaderFile(const qmt::MElement *element) override;
+ void openHeaderFile(const qmt::DElement *element, const qmt::MDiagram *diagram) override;
+ void openSourceFile(const qmt::MElement *element) override;
+ void openSourceFile(const qmt::DElement *element, const qmt::MDiagram *diagram) override;
+
+ bool hasFolder(const qmt::MElement *element) const override;
+ bool hasFolder(const qmt::DElement *element, const qmt::MDiagram *diagram) const override;
+ void showFolder(const qmt::MElement *element) override;
+ void showFolder(const qmt::DElement *element, const qmt::MDiagram *diagram) override;
+
+ bool hasDiagram(const qmt::MElement *element) const override;
+ bool hasDiagram(const qmt::DElement *element, const qmt::MDiagram *diagram) const override;
+ void openDiagram(const qmt::MElement *element) override;
+ void openDiagram(const qmt::DElement *element, const qmt::MDiagram *diagram) override;
+
+ bool mayCreateDiagram(const qmt::MElement *element) const override;
+ bool mayCreateDiagram(const qmt::DElement *element,
+ const qmt::MDiagram *diagram) const override;
+ void createAndOpenDiagram(const qmt::MElement *element) override;
+ void createAndOpenDiagram(const qmt::DElement *element, const qmt::MDiagram *diagram) override;
+
+private:
+ ElementTasksPrivate *d;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // ELEMENTTASKS_H
diff --git a/src/plugins/modeleditor/extdocumentcontroller.cpp b/src/plugins/modeleditor/extdocumentcontroller.cpp
new file mode 100644
index 00000000000..7797a56f3c6
--- /dev/null
+++ b/src/plugins/modeleditor/extdocumentcontroller.cpp
@@ -0,0 +1,89 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "extdocumentcontroller.h"
+
+#include "elementtasks.h"
+#include "pxnodecontroller.h"
+
+#include "qmt/project_controller/projectcontroller.h"
+#include "qmt/tasks/diagramscenecontroller.h"
+
+#include <QFileInfo>
+
+namespace ModelEditor {
+namespace Internal {
+
+class ExtDocumentController::ExtDocumentControllerPrivate {
+public:
+ ElementTasks *elementTasks = 0;
+ PxNodeController *pxNodeController = 0;
+};
+
+ExtDocumentController::ExtDocumentController(QObject *parent)
+ : qmt::DocumentController(parent),
+ d(new ExtDocumentControllerPrivate)
+{
+ d->elementTasks = new ElementTasks;
+ d->pxNodeController = new PxNodeController(this);
+ // TODO use more specific dependency
+ d->elementTasks->setDocumentController(this);
+ getDiagramSceneController()->setElementTasks(d->elementTasks);
+
+ d->pxNodeController->setDiagramSceneController(getDiagramSceneController());
+
+ connect(getProjectController(), &qmt::ProjectController::fileNameChanged,
+ this, &ExtDocumentController::onProjectFileNameChanged);
+}
+
+ExtDocumentController::~ExtDocumentController()
+{
+ delete d->elementTasks;
+ delete d;
+}
+
+ElementTasks *ExtDocumentController::elementTasks() const
+{
+ return d->elementTasks;
+}
+
+PxNodeController *ExtDocumentController::pxNodeController() const
+{
+ return d->pxNodeController;
+}
+
+void ExtDocumentController::onProjectFileNameChanged(const QString &fileName)
+{
+ QFileInfo fileInfo(fileName);
+ d->pxNodeController->setAnchorFolder(fileInfo.path());
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/extdocumentcontroller.h b/src/plugins/modeleditor/extdocumentcontroller.h
new file mode 100644
index 00000000000..0240c282a8a
--- /dev/null
+++ b/src/plugins/modeleditor/extdocumentcontroller.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef EXTDOCUMENTCONTROLLER_H
+#define EXTDOCUMENTCONTROLLER_H
+
+#include "qmt/document_controller/documentcontroller.h"
+
+namespace ModelEditor {
+namespace Internal {
+
+class ElementTasks;
+class PxNodeController;
+
+class ExtDocumentController :
+ public qmt::DocumentController
+{
+ Q_OBJECT
+ class ExtDocumentControllerPrivate;
+
+public:
+ explicit ExtDocumentController(QObject *parent = 0);
+ ~ExtDocumentController();
+
+ ElementTasks *elementTasks() const;
+ PxNodeController *pxNodeController() const;
+
+private slots:
+ void onProjectFileNameChanged(const QString &fileName);
+
+private:
+ ExtDocumentControllerPrivate *d;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // EXTDOCUMENTCONTROLLER_H
diff --git a/src/plugins/modeleditor/modeldocument.cpp b/src/plugins/modeleditor/modeldocument.cpp
new file mode 100644
index 00000000000..8814559a25a
--- /dev/null
+++ b/src/plugins/modeleditor/modeldocument.cpp
@@ -0,0 +1,192 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "modeldocument.h"
+
+#include "modeleditor_constants.h"
+#include "modeleditor_plugin.h"
+#include "modelsmanager.h"
+#include "extdocumentcontroller.h"
+
+#include "qmt/infrastructure/ioexceptions.h"
+#include "qmt/model_controller/modelcontroller.h"
+#include "qmt/model/mdiagram.h"
+#include "qmt/project_controller/projectcontroller.h"
+#include "qmt/project/project.h"
+
+#include <coreplugin/id.h>
+#include <utils/fileutils.h>
+
+#include <QFileInfo>
+
+namespace ModelEditor {
+namespace Internal {
+
+class ModelDocument::ModelDocumentPrivate {
+public:
+ ExtDocumentController *documentController = 0;
+ qmt::Uid diagramUid;
+};
+
+ModelDocument::ModelDocument(QObject *parent)
+ : Core::IDocument(parent),
+ d(new ModelDocumentPrivate)
+{
+ setId(ModelEditor::Constants::MODEL_EDITOR_ID);
+ setMimeType(QLatin1String(Constants::MIME_TYPE_MODEL));
+}
+
+ModelDocument::~ModelDocument()
+{
+ if (d->documentController)
+ ModelEditorPlugin::modelsManager()->release(d->documentController, this);
+ delete d;
+}
+
+Core::IDocument::OpenResult ModelDocument::open(QString *errorString, const QString &fileName,
+ const QString &realFileName)
+{
+ Q_UNUSED(fileName);
+
+ if (!load(errorString, realFileName))
+ return Core::IDocument::OpenResult::ReadError;
+ return Core::IDocument::OpenResult::Success;
+}
+
+bool ModelDocument::save(QString *errorString, const QString &name, bool autoSave)
+{
+ if (!d->documentController) {
+ *errorString = tr("No model loaded. Cannot save.");
+ return false;
+ }
+
+ QString actualName = filePath().toString();
+ if (!name.isEmpty())
+ actualName = name;
+ d->documentController->getProjectController()->setFileName(actualName);
+ try {
+ d->documentController->getProjectController()->save();
+ } catch (const qmt::Exception &ex) {
+ *errorString = ex.getErrorMsg();
+ return false;
+ }
+
+ if (!autoSave) {
+ setFilePath(Utils::FileName::fromString(d->documentController->getProjectController()->getProject()->getFileName()));
+ emit changed();
+ }
+
+ onDiagramRenamed();
+ return true;
+}
+
+QString ModelDocument::defaultPath() const
+{
+ return QLatin1String(".");
+}
+
+QString ModelDocument::suggestedFileName() const
+{
+ return tr("model.qmodel");
+}
+
+bool ModelDocument::isModified() const
+{
+ return d->documentController ? d->documentController->getProjectController()->isModified() : false;
+}
+
+bool ModelDocument::isSaveAsAllowed() const
+{
+ return true;
+}
+
+bool ModelDocument::reload(QString *errorString, Core::IDocument::ReloadFlag flag,
+ Core::IDocument::ChangeType type)
+{
+ if (flag == FlagIgnore)
+ return true;
+ if (type == TypePermissions) {
+ emit changed();
+ return true;
+ }
+ *errorString = tr("Cannot reload model file.");
+ return false;
+}
+
+ExtDocumentController *ModelDocument::documentController() const
+{
+ return d->documentController;
+}
+
+qmt::Uid ModelDocument::diagramUid() const
+{
+ return d->diagramUid;
+}
+
+bool ModelDocument::load(QString *errorString, const QString &fileName)
+{
+ d->documentController = ModelEditorPlugin::modelsManager()->findModelByFileName(fileName, this);
+ if (d->documentController) {
+ connect(d->documentController, &qmt::DocumentController::changed,
+ this, &IDocument::changed);
+ setFilePath(Utils::FileName::fromString(d->documentController->getProjectController()->getProject()->getFileName()));
+ } else {
+ d->documentController = ModelEditorPlugin::modelsManager()->createModel(this);
+ connect(d->documentController, &qmt::DocumentController::changed,
+ this, &IDocument::changed);
+
+ try {
+ d->documentController->loadProject(fileName);
+ setFilePath(Utils::FileName::fromString(d->documentController->getProjectController()->getProject()->getFileName()));
+ } catch (const qmt::Exception &ex) {
+ *errorString = ex.getErrorMsg();
+ return false;
+ }
+ }
+
+ qmt::MDiagram *rootDiagram = d->documentController->findOrCreateRootDiagram();
+ d->diagramUid = rootDiagram->getUid();
+
+ onDiagramRenamed();
+ emit contentSet();
+ return true;
+}
+
+void ModelDocument::onDiagramRenamed()
+{
+ qmt::MDiagram *diagram = d->documentController->getModelController()->findObject<qmt::MDiagram>(d->diagramUid);
+ if (diagram)
+ setPreferredDisplayName(tr("%1 [%2]").arg(diagram->getName()).arg(filePath().fileName()));
+ else
+ setPreferredDisplayName(QString());
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/modeldocument.h b/src/plugins/modeleditor/modeldocument.h
new file mode 100644
index 00000000000..dc422700475
--- /dev/null
+++ b/src/plugins/modeleditor/modeldocument.h
@@ -0,0 +1,80 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef MODELDOCUMENT_H
+#define MODELDOCUMENT_H
+
+#include <coreplugin/idocument.h>
+#include "documentinterface.h"
+
+namespace ModelEditor {
+namespace Internal {
+
+class ExtDocumentController;
+
+class ModelDocument :
+ public Core::IDocument,
+ public DocumentInterface
+{
+ Q_OBJECT
+ class ModelDocumentPrivate;
+
+public:
+ explicit ModelDocument(QObject *parent = 0);
+ ~ModelDocument();
+
+signals:
+ void contentSet();
+
+public:
+ IDocument::OpenResult open(QString *errorString, const QString &fileName,
+ const QString &realFileName) override;
+ bool save(QString *errorString, const QString &fileName, bool autoSave) override;
+ QString defaultPath() const override;
+ QString suggestedFileName() const override;
+ bool isModified() const override;
+ bool isSaveAsAllowed() const override;
+ bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override;
+
+ ExtDocumentController *documentController() const override;
+ qmt::Uid diagramUid() const override;
+
+ bool load(QString *errorString, const QString &fileName);
+
+ void onDiagramRenamed();
+
+private:
+ ModelDocumentPrivate *d;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // MODELDOCUMENT_H
diff --git a/src/plugins/modeleditor/modeleditor.cpp b/src/plugins/modeleditor/modeleditor.cpp
new file mode 100644
index 00000000000..e2a66ac98d3
--- /dev/null
+++ b/src/plugins/modeleditor/modeleditor.cpp
@@ -0,0 +1,84 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "modeleditor.h"
+
+#include "modeleditor_constants.h"
+#include "modeldocument.h"
+#include "extdocumentcontroller.h"
+
+#include "qmt/diagram_ui/diagramsmanager.h"
+#include "qmt/model/mcanvasdiagram.h"
+#include "qmt/model_controller/modelcontroller.h"
+
+#include <QFileInfo>
+
+namespace ModelEditor {
+namespace Internal {
+
+class ModelEditor::ModelEditorPrivate
+{
+public:
+ ModelDocument *document = 0;
+};
+
+ModelEditor::ModelEditor(UiController *uiController, ActionHandler *actionHandler, QWidget *parent)
+ : AbstractEditor(uiController, actionHandler, parent),
+ d(new ModelEditorPrivate)
+{
+ setContext(Core::Context(Constants::MODEL_EDITOR_ID));
+ d->document = new ModelDocument(this);
+ connect(d->document, &ModelDocument::contentSet, this, &ModelEditor::onContentSet);
+ init(parent);
+}
+
+ModelEditor::~ModelEditor()
+{
+ delete d;
+}
+
+Core::IDocument *ModelEditor::document()
+{
+ return d->document;
+}
+
+void ModelEditor::onContentSet()
+{
+ setDocument(d->document);
+
+ // open diagram
+ qmt::MDiagram *rootDiagram = d->document->documentController()->findOrCreateRootDiagram();
+ showDiagram(rootDiagram);
+
+ expandModelTreeToDepth(0);
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/modeleditor.h b/src/plugins/modeleditor/modeleditor.h
new file mode 100644
index 00000000000..9cfcf05236c
--- /dev/null
+++ b/src/plugins/modeleditor/modeleditor.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef MODELDIAGRAMEDITOR_H
+#define MODELDIAGRAMEDITOR_H
+
+#include "abstracteditor.h"
+
+namespace ModelEditor {
+namespace Internal {
+
+class ModelEditor :
+ public AbstractEditor
+{
+ Q_OBJECT
+ class ModelEditorPrivate;
+
+public:
+ explicit ModelEditor(UiController *uiController, ActionHandler *actionHandler,
+ QWidget *parent = 0);
+ ~ModelEditor();
+
+ Core::IDocument *document() override;
+
+private slots:
+ void onContentSet();
+
+private:
+ ModelEditorPrivate *d;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // MODELDIAGRAMEDITOR_H
diff --git a/src/plugins/modeleditor/modeleditor.pro b/src/plugins/modeleditor/modeleditor.pro
new file mode 100644
index 00000000000..6832fe2b277
--- /dev/null
+++ b/src/plugins/modeleditor/modeleditor.pro
@@ -0,0 +1,90 @@
+include(../../qtcreatorplugin.pri)
+
+DEFINES += MODELEDITOR_LIBRARY
+
+QT += core gui widgets
+
+!win32:CONFIG(pdf) {
+ DEFINES += USE_PDF_CLIPBOARD
+}
+
+!win32:CONFIG(svg): {
+ QT += svg
+ DEFINES += USE_SVG_CLIPBOARD
+}
+
+#win32:CONFIG(emf): {
+# DEFINES += USE_EMF USE_EMF_CLIPBOARD
+#
+# SOURCES += \
+# emf-engine/qemfpaintengine.cpp \
+# emf-engine/qemfwriter.cpp
+#
+# HEADERS += \
+# emf-engine/qemfpaintengine.h \
+# emf-engine/qemfwriter.h
+#
+#}
+
+SOURCES += \
+ abstracteditor.cpp \
+ actionhandler.cpp \
+ classviewcontroller.cpp \
+ componentviewcontroller.cpp \
+ diagramdocument.cpp \
+ diagrameditor.cpp \
+ diagrameditorfactory.cpp \
+ diagramsviewmanager.cpp \
+ dragtool.cpp \
+ editordiagramview.cpp \
+ elementtasks.cpp \
+ extdocumentcontroller.cpp \
+ modeldocument.cpp \
+ modeleditor.cpp \
+ modeleditorfactory.cpp \
+ modeleditor_file_wizard.cpp \
+ modeleditor_plugin.cpp \
+ modelindexer.cpp \
+ modelsmanager.cpp \
+ openelementvisitor.cpp \
+ pxnodecontroller.cpp \
+ pxnodeutilities.cpp \
+ settingscontroller.cpp \
+ uicontroller.cpp
+
+HEADERS += \
+ abstracteditor.h \
+ actionhandler.h \
+ classviewcontroller.h \
+ componentviewcontroller.h \
+ diagramdocument.h \
+ diagrameditorfactory.h \
+ diagrameditor.h \
+ diagramsviewmanager.h \
+ documentinterface.h \
+ dragtool.h \
+ editordiagramview.h \
+ elementtasks.h \
+ extdocumentcontroller.h \
+ modeldocument.h \
+ modeleditor_constants.h \
+ modeleditorfactory.h \
+ modeleditor_file_wizard.h \
+ modeleditor_global.h \
+ modeleditor.h \
+ modeleditor_plugin.h \
+ modelindexer.h \
+ modelsmanager.h \
+ openelementvisitor.h \
+ pxnodecontroller.h \
+ pxnodeutilities.h \
+ settingscontroller.h \
+ uicontroller.h
+
+OTHER_FILES += \
+ ModelEditor.json.in
+
+RESOURCES += \
+ resources/modeleditor.qrc
+
+FORMS +=
diff --git a/src/plugins/modeleditor/modeleditor.qbs b/src/plugins/modeleditor/modeleditor.qbs
new file mode 100644
index 00000000000..cad53935343
--- /dev/null
+++ b/src/plugins/modeleditor/modeleditor.qbs
@@ -0,0 +1,75 @@
+import qbs.base 1.0
+
+import QtcPlugin
+
+QtcPlugin {
+ name: "ModelEditor"
+
+ Depends { name: "Qt.widgets" }
+ Depends { name: "Core" }
+ Depends { name: "CPlusPlus" }
+ Depends { name: "CppTools" }
+ Depends { name: "ProjectExplorer" }
+ Depends { name: "ModelingLib" }
+
+ cpp.includePaths: [
+ "qmt",
+ "qstringparser",
+ "qtserialization",
+ ]
+
+ files: [
+ "abstracteditor.cpp",
+ "abstracteditor.h",
+ "actionhandler.cpp",
+ "actionhandler.h",
+ "classviewcontroller.cpp",
+ "classviewcontroller.h",
+ "componentviewcontroller.cpp",
+ "componentviewcontroller.h",
+ "diagramdocument.cpp",
+ "diagramdocument.h",
+ "diagrameditor.cpp",
+ "diagrameditorfactory.cpp",
+ "diagrameditorfactory.h",
+ "diagrameditor.h",
+ "diagramsviewmanager.cpp",
+ "diagramsviewmanager.h",
+ "documentinterface.h",
+ "dragtool.cpp",
+ "dragtool.h",
+ "editordiagramview.cpp",
+ "editordiagramview.h",
+ "elementtasks.cpp",
+ "elementtasks.h",
+ "extdocumentcontroller.cpp",
+ "extdocumentcontroller.h",
+ "modeldocument.cpp",
+ "modeldocument.h",
+ "modeleditor_constants.h",
+ "modeleditor.cpp",
+ "modeleditorfactory.cpp",
+ "modeleditorfactory.h",
+ "modeleditor_file_wizard.cpp",
+ "modeleditor_file_wizard.h",
+ "modeleditor_global.h",
+ "modeleditor.h",
+ "modeleditor_plugin.cpp",
+ "modeleditor_plugin.h",
+ "modelindexer.cpp",
+ "modelindexer.h",
+ "modelsmanager.cpp",
+ "modelsmanager.h",
+ "openelementvisitor.cpp",
+ "openelementvisitor.h",
+ "pxnodecontroller.cpp",
+ "pxnodecontroller.h",
+ "pxnodeutilities.cpp",
+ "pxnodeutilities.h",
+ "resources/modeleditor.qrc",
+ "settingscontroller.cpp",
+ "settingscontroller.h",
+ "uicontroller.cpp",
+ "uicontroller.h",
+ ]
+}
diff --git a/src/plugins/modeleditor/modeleditor_constants.h b/src/plugins/modeleditor/modeleditor_constants.h
new file mode 100644
index 00000000000..baee8643079
--- /dev/null
+++ b/src/plugins/modeleditor/modeleditor_constants.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef MODELEDITORCONSTANTS_H
+#define MODELEDITORCONSTANTS_H
+
+namespace ModelEditor {
+namespace Constants {
+
+const char MODEL_EDITOR_ID[] = "Editors.ModelEditor";
+const char MODEL_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("OpenWith::Editors", "Model Editor");
+
+const char DIAGRAM_EDITOR_ID[] = "Editors.DiagramEditor";
+const char DIAGRAM_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("OpenWith::Editors", "Model Editor");
+
+const char REMOVE_SELECTED_ELEMENTS[] = "ModelEditor.RemoveSelectedElements";
+const char DELETE_SELECTED_ELEMENTS[] = "ModelEditor.DeleteSelectedElements";
+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 EXPLORER_GROUP_MODELING[] = "ModelEditor.ProjectFolder.Group.Modeling";
+const char ACTION_EXPLORER_OPEN_DIAGRAM[] = "ModelEditor.Action.Explorer.OpenDiagram";
+
+const char SHORTCUT_MODEL_EDITOR_EDIT_PROPERTIES[] =
+ "ModelEditor.ModelEditor.Shortcut.EditProperties";
+const char SHORTCUT_DIAGRAM_EDITOR_EDIT_PROPERTIES[] =
+ "ModelEditor.DiagramEditor.Shortcut.EditProperties";
+
+const char WIZARD_CATEGORY[] = "O.Model";
+const char WIZARD_TR_CATEGORY[] = QT_TRANSLATE_NOOP("Modeling", "Modeling");
+const char WIZARD_MODEL_ID[] = "SA.Model";
+
+const char MIME_TYPE_MODEL[] = "text/vnd.qtcreator.model";
+const char MIME_TYPE_DIAGRAM_REFERENCE[] = "text/vnd.qtcreator.diagram-reference";
+
+// Settings entries
+const char SETTINGS_GROUP[] = "ModelEditorPlugin";
+const char SETTINGS_RIGHT_SPLITTER[] = "RightSplitter";
+const char SETTINGS_RIGHT_HORIZ_SPLITTER[] = "RightHorizSplitter";
+
+} // namespace Constants
+} // namespace ModelEditor
+
+#endif // MODELEDITORCONSTANTS_H
diff --git a/src/plugins/modeleditor/modeleditor_dependencies.pri b/src/plugins/modeleditor/modeleditor_dependencies.pri
new file mode 100644
index 00000000000..61fffe30433
--- /dev/null
+++ b/src/plugins/modeleditor/modeleditor_dependencies.pri
@@ -0,0 +1,12 @@
+QTC_PLUGIN_NAME = ModelEditor
+
+QTC_LIB_DEPENDS += \
+ cplusplus \
+ extensionsystem \
+ modelinglib \
+ utils
+
+QTC_PLUGIN_DEPENDS += \
+ coreplugin \
+ cpptools \
+ projectexplorer
diff --git a/src/plugins/modeleditor/modeleditor_file_wizard.cpp b/src/plugins/modeleditor/modeleditor_file_wizard.cpp
new file mode 100644
index 00000000000..1ca54d40d5e
--- /dev/null
+++ b/src/plugins/modeleditor/modeleditor_file_wizard.cpp
@@ -0,0 +1,128 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "modeleditor_file_wizard.h"
+
+#include "modeleditor_constants.h"
+
+#include "qmt/controller/namecontroller.h"
+#include "qmt/model/mcanvasdiagram.h"
+#include "qmt/model/mpackage.h"
+#include "qmt/serializer/projectserializer.h"
+#include "qmt/project/project.h"
+
+#include <coreplugin/basefilewizard.h>
+#include <utils/filewizardpage.h>
+#include <utils/qtcassert.h>
+
+#include <QCoreApplication>
+
+namespace ModelEditor {
+namespace Internal {
+
+FileWizardFactory::FileWizardFactory()
+ : Core::BaseFileWizardFactory()
+{
+ setWizardKind(Core::IWizardFactory::FileWizard);
+ setCategory(QLatin1String(Constants::WIZARD_CATEGORY));
+ QString trCategory = QCoreApplication::translate(Constants::WIZARD_CATEGORY,
+ Constants::WIZARD_TR_CATEGORY);
+ setDisplayCategory(trCategory);
+ setDisplayName(tr("Model"));
+ setId(Constants::WIZARD_MODEL_ID);
+ setDescription(tr("Creates an empty model"));
+ setFlags(Core::IWizardFactory::PlatformIndependent);
+}
+
+Core::BaseFileWizard *FileWizardFactory::create(
+ QWidget *parent, const Core::WizardDialogParameters &parameters) const
+{
+ auto wizard = new Core::BaseFileWizard(this, QVariantMap(), parent);
+ wizard->setWindowTitle(tr("New %1").arg(displayName()));
+
+ auto page = new Utils::FileWizardPage;
+ if (parameters.flags().testFlag(Core::WizardDialogParameters::ForceCapitalLetterForFileName))
+ page->setForceFirstCapitalLetterForFileName(true);
+ page->setTitle(tr("Model Name and Location"));
+ page->setFileNameLabel(tr("Model name:"));
+ page->setPathLabel(tr("Location:"));
+ page->setPath(parameters.defaultPath());
+ wizard->addPage(page);
+
+ foreach (QWizardPage *p, wizard->extensionPages())
+ wizard->addPage(p);
+ return wizard;
+}
+
+Core::GeneratedFiles FileWizardFactory::generateFiles(const QWizard *w,
+ QString *errorMessage) const
+{
+ const Utils::Wizard *wizard = qobject_cast<const Utils::Wizard *>(w);
+ Utils::FileWizardPage *page = wizard->find<Utils::FileWizardPage>();
+ QTC_ASSERT(page, return Core::GeneratedFiles());
+
+ return generateFilesFromPath(page->path(), page->fileName(), errorMessage);
+}
+
+Core::GeneratedFiles FileWizardFactory::generateFilesFromPath(const QString &path,
+ const QString &name,
+ QString *errorMessage) const
+{
+ Q_UNUSED(errorMessage);
+
+ Core::GeneratedFiles files;
+
+ const QString suffix = preferredSuffix(QLatin1String(Constants::MIME_TYPE_MODEL));
+ const QString fileName = Core::BaseFileWizardFactory::buildFileName(path, name, suffix);
+ Core::GeneratedFile file(fileName);
+
+ auto rootPackage = new qmt::MPackage();
+ rootPackage->setName(qmt::NameController::convertFileNameToElementName(fileName));
+
+ auto rootDiagram = new qmt::MCanvasDiagram();
+ rootDiagram->setName(qmt::NameController::convertFileNameToElementName(fileName));
+ rootPackage->addChild(rootDiagram);
+
+ qmt::Project project;
+ project.setRootPackage(rootPackage);
+ project.setFileName(fileName);
+
+ qmt::ProjectSerializer serializer;
+ QByteArray contents = serializer.save(&project);
+
+ file.setContents(QString::fromUtf8(contents));
+ file.setAttributes(Core::GeneratedFile::OpenEditorAttribute);
+
+ files << file;
+ return files;
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/modeleditor_file_wizard.h b/src/plugins/modeleditor/modeleditor_file_wizard.h
new file mode 100644
index 00000000000..f713d935c43
--- /dev/null
+++ b/src/plugins/modeleditor/modeleditor_file_wizard.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef MODELEDITOR_FILE_WIZARD_H
+#define MODELEDITOR_FILE_WIZARD_H
+
+#include <coreplugin/basefilewizardfactory.h>
+
+namespace ModelEditor {
+namespace Internal {
+
+class FileWizardFactory :
+ public Core::BaseFileWizardFactory
+{
+ Q_OBJECT
+
+public:
+ explicit FileWizardFactory();
+
+protected:
+ Core::BaseFileWizard *create(QWidget *parent,
+ const Core::WizardDialogParameters &parameters) const override;
+ Core::GeneratedFiles generateFiles(const QWizard *w, QString *errorMessage) const override;
+
+private:
+ Core::GeneratedFiles generateFilesFromPath(const QString &path, const QString &name,
+ QString *errorMessage) const;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // MODELEDITOR_FILE_WIZARD_H
diff --git a/src/plugins/modeleditor/modeleditor_global.h b/src/plugins/modeleditor/modeleditor_global.h
new file mode 100644
index 00000000000..f8a905013f0
--- /dev/null
+++ b/src/plugins/modeleditor/modeleditor_global.h
@@ -0,0 +1,42 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef MODELEDITOR_GLOBAL_H
+#define MODELEDITOR_GLOBAL_H
+
+#include <QtGlobal>
+
+#if defined(MODELEDITOR_LIBRARY)
+# define MODELEDITOR_EXPORT Q_DECL_EXPORT
+#else
+# define MODELEDITOR_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // MODELEDITOR_GLOBAL_H
diff --git a/src/plugins/modeleditor/modeleditor_plugin.cpp b/src/plugins/modeleditor/modeleditor_plugin.cpp
new file mode 100644
index 00000000000..ef917e149dd
--- /dev/null
+++ b/src/plugins/modeleditor/modeleditor_plugin.cpp
@@ -0,0 +1,151 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "modeleditor_plugin.h"
+
+#include "diagrameditorfactory.h"
+#include "modeleditorfactory.h"
+#include "modelsmanager.h"
+#include "settingscontroller.h"
+#include "modeleditor_constants.h"
+#include "modeleditor_file_wizard.h"
+#include "uicontroller.h"
+
+#include "qmt/infrastructure/uid.h"
+
+#include <coreplugin/actionmanager/actioncontainer.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/actionmanager/command.h>
+#include <coreplugin/basefilewizard.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/icontext.h>
+#include <coreplugin/icore.h>
+
+#include <utils/mimetypes/mimedatabase.h>
+
+#include <QAction>
+#include <QApplication>
+#include <QMessageBox>
+#include <QMainWindow>
+#include <QMenu>
+#include <QItemSelection>
+#include <QClipboard>
+#include <QFontDatabase>
+
+#include <QtPlugin>
+
+namespace ModelEditor {
+namespace Internal {
+
+ModelEditorPlugin *pluginInstance = 0;
+
+class ModelEditorPlugin::ModelEditorPluginPrivate
+{
+public:
+ ModelsManager *modelsManager = 0;
+ UiController *uiController = 0;
+ ModelEditorFactory *modelFactory = 0;
+ DiagramEditorFactory *diagramFactory = 0;
+ SettingsController *settingsController = 0;
+};
+
+ModelEditorPlugin::ModelEditorPlugin()
+ : ExtensionSystem::IPlugin(),
+ d(new ModelEditorPluginPrivate)
+{
+ pluginInstance = this;
+ qRegisterMetaType<QItemSelection>("QItemSelection");
+ qRegisterMetaType<qmt::Uid>("qmt::Uid");
+}
+
+ModelEditorPlugin::~ModelEditorPlugin()
+{
+ delete d;
+}
+
+bool ModelEditorPlugin::initialize(const QStringList &arguments, QString *errorString)
+{
+ Q_UNUSED(arguments);
+ Q_UNUSED(errorString);
+
+ Utils::MimeDatabase::addMimeTypes(QStringLiteral(":/modeleditor/modeleditor.mimetypes.xml"));
+
+ d->modelsManager = new ModelsManager(this);
+ addAutoReleasedObject(d->modelsManager);
+
+ d->uiController = new UiController(this);
+ addAutoReleasedObject(d->uiController);
+
+ Core::IWizardFactory::registerFactoryCreator([]() {
+ return QList<Core::IWizardFactory *>() << new FileWizardFactory;
+ });
+
+ d->modelFactory = new ModelEditorFactory(d->uiController, this);
+ addAutoReleasedObject(d->modelFactory);
+
+ d->diagramFactory = new DiagramEditorFactory(d->uiController, this);
+ addAutoReleasedObject(d->diagramFactory);
+
+ d->settingsController = new SettingsController(this);
+ addAutoReleasedObject(d->settingsController);
+
+ connect(d->settingsController, &SettingsController::saveSettings,
+ d->uiController, &UiController::saveSettings);
+ connect(d->settingsController, &SettingsController::loadSettings,
+ d->uiController, &UiController::loadSettings);
+
+ return true;
+}
+
+void ModelEditorPlugin::extensionsInitialized()
+{
+ // Retrieve objects from the plugin manager's object pool
+ // In the extensionsInitialized method, a plugin can be sure that all
+ // plugins that depend on it are completely initialized.
+ d->modelFactory->extensionsInitialized();
+ d->diagramFactory->extensionsInitialized();
+ d->settingsController->load(Core::ICore::settings());
+}
+
+ExtensionSystem::IPlugin::ShutdownFlag ModelEditorPlugin::aboutToShutdown()
+{
+ d->settingsController->save(Core::ICore::settings());
+ QApplication::clipboard()->clear();
+ return SynchronousShutdown;
+}
+
+ModelsManager *ModelEditorPlugin::modelsManager()
+{
+ return pluginInstance->d->modelsManager;
+}
+
+} // namespace Internal
+} // namespace ModelEditor
+
diff --git a/src/plugins/modeleditor/modeleditor_plugin.h b/src/plugins/modeleditor/modeleditor_plugin.h
new file mode 100644
index 00000000000..a52414acf56
--- /dev/null
+++ b/src/plugins/modeleditor/modeleditor_plugin.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef MODELEDITORPLUGIN_H
+#define MODELEDITORPLUGIN_H
+
+#include "modeleditor_global.h"
+
+#include <extensionsystem/iplugin.h>
+
+namespace ModelEditor {
+namespace Internal {
+
+class ModelsManager;
+
+class ModelEditorPlugin :
+ public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "ModelEditor.json")
+ class ModelEditorPluginPrivate;
+
+public:
+ ModelEditorPlugin();
+ ~ModelEditorPlugin();
+
+ bool initialize(const QStringList &arguments, QString *errorString) override;
+ void extensionsInitialized() override;
+ ShutdownFlag aboutToShutdown() override;
+
+ static ModelsManager *modelsManager();
+
+private:
+ ModelEditorPluginPrivate *d;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // MODELEDITORPLUGIN_H
diff --git a/src/plugins/modeleditor/modeleditorfactory.cpp b/src/plugins/modeleditor/modeleditorfactory.cpp
new file mode 100644
index 00000000000..acf1399aa4e
--- /dev/null
+++ b/src/plugins/modeleditor/modeleditorfactory.cpp
@@ -0,0 +1,79 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "modeleditorfactory.h"
+
+#include "modeleditor_constants.h"
+#include "actionhandler.h"
+#include "modeleditor.h"
+
+#include <QApplication>
+
+namespace ModelEditor {
+namespace Internal {
+
+class ModelEditorFactory::ModelEditorFactoryPrivate
+{
+public:
+ UiController *uiController = 0;
+ ActionHandler *actionHandler = 0;
+};
+
+ModelEditorFactory::ModelEditorFactory(UiController *uiController, QObject *parent)
+ : Core::IEditorFactory(parent),
+ d(new ModelEditorFactoryPrivate())
+{
+ setId(Constants::MODEL_EDITOR_ID);
+ setDisplayName(qApp->translate("OpenWith::Editors", Constants::MODEL_EDITOR_DISPLAY_NAME));
+ addMimeType(Constants::MIME_TYPE_MODEL);
+ d->uiController = uiController;
+ d->actionHandler = new ActionHandler(Core::Context(Constants::MODEL_EDITOR_ID), this);
+}
+
+ModelEditorFactory::~ModelEditorFactory()
+{
+ delete d->actionHandler;
+ delete d;
+}
+
+Core::IEditor *ModelEditorFactory::createEditor()
+{
+ return new ModelEditor(d->uiController, d->actionHandler);
+}
+
+void ModelEditorFactory::extensionsInitialized()
+{
+ d->actionHandler->createActions();
+ d->actionHandler->createEditPropertiesShortcut(
+ Constants::SHORTCUT_MODEL_EDITOR_EDIT_PROPERTIES);
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/modeleditorfactory.h b/src/plugins/modeleditor/modeleditorfactory.h
new file mode 100644
index 00000000000..3bbfe44f4e4
--- /dev/null
+++ b/src/plugins/modeleditor/modeleditorfactory.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef STRUCTUREDIAGRAMEDITORFACTORY_H
+#define STRUCTUREDIAGRAMEDITORFACTORY_H
+
+#include <coreplugin/editormanager/ieditorfactory.h>
+
+namespace ModelEditor {
+namespace Internal {
+
+class ModelEditor;
+class UiController;
+
+class ModelEditorFactory :
+ public Core::IEditorFactory
+{
+ Q_OBJECT
+ class ModelEditorFactoryPrivate;
+
+public:
+ explicit ModelEditorFactory(UiController *uiController, QObject *parent = 0);
+ ~ModelEditorFactory();
+
+ Core::IEditor *createEditor() override;
+ void extensionsInitialized();
+
+private:
+ ModelEditorFactoryPrivate *d;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // STRUCTUREDIAGRAMEDITORFACTORY_H
diff --git a/src/plugins/modeleditor/modelindexer.cpp b/src/plugins/modeleditor/modelindexer.cpp
new file mode 100644
index 00000000000..a0b346dc39f
--- /dev/null
+++ b/src/plugins/modeleditor/modelindexer.cpp
@@ -0,0 +1,615 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "modelindexer.h"
+
+#include "modeleditor_constants.h"
+
+#include "qmt/infrastructure/uid.h"
+
+#include "qmt/serializer/projectserializer.h"
+#include "qmt/serializer/diagramreferenceserializer.h"
+
+#include "qmt/project/project.h"
+#include "qmt/model_controller/mvoidvisitor.h"
+#include "qmt/model/mpackage.h"
+#include "qmt/model/mdiagram.h"
+
+#include "qmt/tasks/findrootdiagramvisitor.h"
+
+#include <projectexplorer/project.h>
+#include <projectexplorer/session.h>
+#include <projectexplorer/projectnodes.h>
+
+#include <utils/mimetypes/mimetype.h>
+#include <utils/mimetypes/mimedatabase.h>
+#include <utils/qtcassert.h>
+
+#include <QQueue>
+#include <QMutex>
+#include <QMutexLocker>
+#include <QThread>
+#include <QDateTime>
+
+#include <QLoggingCategory>
+#include <QDebug>
+
+namespace ModelEditor {
+namespace Internal {
+
+class ModelIndexer::QueuedFile
+{
+ friend uint qHash(const ModelIndexer::QueuedFile &queuedFile);
+ friend bool operator==(const ModelIndexer::QueuedFile &lhs,
+ const ModelIndexer::QueuedFile &rhs);
+
+public:
+ enum FileType {
+ UNKNOWN_FILE_TYPE,
+ MODEL_FILE,
+ // TODO remove type because it is not longer used
+ DIAGRAM_FILE
+ };
+
+ QueuedFile() = default;
+
+ QueuedFile(const QString &file, ProjectExplorer::Project *project)
+ : m_file(file),
+ m_project(project),
+ m_fileType(UNKNOWN_FILE_TYPE)
+ {
+ }
+
+ QueuedFile(const QString &file, ProjectExplorer::Project *project, FileType fileType,
+ const QDateTime &lastModified)
+ : m_file(file),
+ m_project(project),
+ m_fileType(fileType),
+ m_lastModified(lastModified)
+ {
+ }
+
+ bool isValid() const { return !m_file.isEmpty() && m_project; }
+ QString file() const { return m_file; }
+ ProjectExplorer::Project *project() const { return m_project; }
+ FileType fileType() const { return m_fileType; }
+ QDateTime lastModified() const { return m_lastModified; }
+
+private:
+ QString m_file;
+ ProjectExplorer::Project *m_project = 0;
+ FileType m_fileType = UNKNOWN_FILE_TYPE;
+ QDateTime m_lastModified;
+};
+
+bool operator==(const ModelIndexer::QueuedFile &lhs, const ModelIndexer::QueuedFile &rhs)
+{
+ return lhs.m_file == rhs.m_file && lhs.m_project == rhs.m_project;
+}
+
+uint qHash(const ModelIndexer::QueuedFile &queuedFile)
+{
+ return qHash(queuedFile.m_project) + qHash(queuedFile.m_project);
+}
+
+class ModelIndexer::IndexedModel
+{
+public:
+ IndexedModel(const QString &modelFile, const QDateTime &lastModified)
+ : m_modelFile(modelFile),
+ m_lastModified(lastModified)
+ {
+ }
+
+ void reset(const QDateTime &lastModified)
+ {
+ m_lastModified = lastModified;
+ m_modelUid = qmt::Uid::getInvalidUid();
+ m_diagrams.clear();
+ }
+
+ QString file() const { return m_modelFile; }
+ QDateTime lastModified() const { return m_lastModified; }
+ QSet<ProjectExplorer::Project *> owningProjects() const { return m_owningProjects; }
+ void addOwningProject(ProjectExplorer::Project *project) { m_owningProjects.insert(project); }
+ void removeOwningProject(ProjectExplorer::Project *project)
+ {
+ m_owningProjects.remove(project);
+ }
+ qmt::Uid modelUid() const { return m_modelUid; }
+ void setModelUid(const qmt::Uid &modelUid) { m_modelUid = modelUid; }
+ QSet<qmt::Uid> diagrams() const { return m_diagrams; }
+ void addDiagram(const qmt::Uid &diagram) { m_diagrams.insert(diagram); }
+
+private:
+ QString m_modelFile;
+ QDateTime m_lastModified;
+ QSet<ProjectExplorer::Project *> m_owningProjects;
+ qmt::Uid m_modelUid;
+ QSet<qmt::Uid> m_diagrams;
+};
+
+class ModelIndexer::IndexedDiagramReference
+{
+public:
+ IndexedDiagramReference(const QString &file, const QDateTime &lastModified)
+ : m_file(file),
+ m_lastModified(lastModified)
+ {
+ }
+
+ void reset(const QDateTime &lastModified)
+ {
+ m_lastModified = lastModified;
+ m_modelUid = qmt::Uid::getInvalidUid();
+ m_diagramUid = qmt::Uid::getInvalidUid();
+ }
+
+ QString file() const { return m_file; }
+ QDateTime lastModified() const { return m_lastModified; }
+ QSet<ProjectExplorer::Project *> owningProjects() const { return m_owningProjects; }
+ void addOwningProject(ProjectExplorer::Project *project) { m_owningProjects.insert(project); }
+ void removeOwningProject(ProjectExplorer::Project *project)
+ {
+ m_owningProjects.remove(project);
+ }
+ qmt::Uid modelUid() const { return m_modelUid; }
+ void setModelUid(const qmt::Uid &modelUid) { m_modelUid = modelUid; }
+ qmt::Uid diagramUid() const { return m_diagramUid; }
+ void setDiagramUid(const qmt::Uid &diagramUid) { m_diagramUid = diagramUid; }
+
+private:
+ QString m_file;
+ QDateTime m_lastModified;
+ QSet<ProjectExplorer::Project *> m_owningProjects;
+ qmt::Uid m_modelUid;
+ qmt::Uid m_diagramUid;
+};
+
+class ModelIndexer::IndexerThread :
+ public QThread
+{
+public:
+ IndexerThread(ModelIndexer *indexer)
+ : QThread(),
+ m_indexer(indexer)
+ {
+ }
+
+ void onQuitIndexerThread();
+ void onFilesQueued();
+
+private:
+ ModelIndexer *m_indexer;
+};
+
+class ModelIndexer::DiagramsCollectorVisitor :
+ public qmt::MVoidConstVisitor
+{
+public:
+ DiagramsCollectorVisitor(ModelIndexer::IndexedModel *indexedModel);
+
+ void visitMObject(const qmt::MObject *object);
+ void visitMDiagram(const qmt::MDiagram *diagram);
+
+private:
+ ModelIndexer::IndexedModel *m_indexedModel;
+};
+
+ModelIndexer::DiagramsCollectorVisitor::DiagramsCollectorVisitor(IndexedModel *indexedModel)
+ : qmt::MVoidConstVisitor(),
+ m_indexedModel(indexedModel)
+{
+}
+
+void ModelIndexer::DiagramsCollectorVisitor::visitMObject(const qmt::MObject *object)
+{
+ foreach (const qmt::Handle<qmt::MObject> &child, object->getChildren()) {
+ if (child.hasTarget())
+ child.getTarget()->accept(this);
+ }
+ visitMElement(object);
+}
+
+void ModelIndexer::DiagramsCollectorVisitor::visitMDiagram(const qmt::MDiagram *diagram)
+{
+ qCDebug(logger) << "add diagram " << diagram->getName() << " to index";
+ m_indexedModel->addDiagram(diagram->getUid());
+ visitMObject(diagram);
+}
+
+class ModelIndexer::ModelIndexerPrivate
+{
+public:
+ ~ModelIndexerPrivate()
+ {
+ QTC_CHECK(filesQueue.isEmpty());
+ QTC_CHECK(queuedFilesSet.isEmpty());
+ QTC_CHECK(indexedModels.isEmpty());
+ QTC_CHECK(indexedModelsByUid.isEmpty());
+ QTC_CHECK(indexedDiagramReferences.isEmpty());
+ QTC_CHECK(indexedDiagramReferencesByDiagramUid.isEmpty());
+ delete indexerThread;
+ }
+
+ QMutex indexerMutex;
+
+ QQueue<ModelIndexer::QueuedFile> filesQueue;
+ QSet<ModelIndexer::QueuedFile> queuedFilesSet;
+ QSet<ModelIndexer::QueuedFile> defaultModelFiles;
+
+ QHash<QString, ModelIndexer::IndexedModel *> indexedModels;
+ QHash<qmt::Uid, QSet<ModelIndexer::IndexedModel *> > indexedModelsByUid;
+
+ QHash<QString, ModelIndexer::IndexedDiagramReference *> indexedDiagramReferences;
+ QHash<qmt::Uid, QSet<ModelIndexer::IndexedDiagramReference *> > indexedDiagramReferencesByDiagramUid;
+
+ ModelIndexer::IndexerThread *indexerThread = 0;
+};
+
+void ModelIndexer::IndexerThread::onQuitIndexerThread()
+{
+ QThread::exit(0);
+}
+
+void ModelIndexer::IndexerThread::onFilesQueued()
+{
+ QMutexLocker locker(&m_indexer->d->indexerMutex);
+
+ while (!m_indexer->d->filesQueue.isEmpty()) {
+ ModelIndexer::QueuedFile queuedFile = m_indexer->d->filesQueue.takeFirst();
+ m_indexer->d->queuedFilesSet.remove(queuedFile);
+ qCDebug(logger) << "handle queued file " << queuedFile.file()
+ << "from project " << queuedFile.project()->displayName();
+
+ switch (queuedFile.fileType()) {
+ case ModelIndexer::QueuedFile::UNKNOWN_FILE_TYPE:
+ QTC_CHECK(false);
+ break;
+ case ModelIndexer::QueuedFile::MODEL_FILE:
+ {
+ bool scanModel = false;
+ IndexedModel *indexedModel = m_indexer->d->indexedModels.value(queuedFile.file());
+ if (!indexedModel) {
+ qCDebug(logger) << "create new indexed model";
+ indexedModel = new IndexedModel(queuedFile.file(),
+ queuedFile.lastModified());
+ indexedModel->addOwningProject(queuedFile.project());
+ m_indexer->d->indexedModels.insert(queuedFile.file(), indexedModel);
+ scanModel = true;
+ } else if (queuedFile.lastModified() > indexedModel->lastModified()) {
+ qCDebug(logger) << "update indexed model";
+ indexedModel->addOwningProject(queuedFile.project());
+ indexedModel->reset(queuedFile.lastModified());
+ scanModel = true;
+ }
+ if (scanModel) {
+ locker.unlock();
+ // load model file
+ qmt::ProjectSerializer projectSerializer;
+ qmt::Project project;
+ projectSerializer.load(queuedFile.file(), &project);
+ locker.relock();
+ indexedModel->setModelUid(project.getUid());
+ // add indexedModel to set of indexedModelsByUid
+ QSet<IndexedModel *> indexedModels = m_indexer->d->indexedModelsByUid.value(project.getUid());
+ indexedModels.insert(indexedModel);
+ m_indexer->d->indexedModelsByUid.insert(project.getUid(), indexedModels);
+ // collect all diagrams of model
+ DiagramsCollectorVisitor visitor(indexedModel);
+ project.getRootPackage()->accept(&visitor);
+ if (m_indexer->d->defaultModelFiles.contains(queuedFile)) {
+ m_indexer->d->defaultModelFiles.remove(queuedFile);
+ // check if model has a diagram which could be opened
+ qmt::FindRootDiagramVisitor diagramVisitor;
+ project.getRootPackage()->accept(&diagramVisitor);
+ if (diagramVisitor.getDiagram())
+ emit m_indexer->openDefaultModel(project.getUid());
+ }
+ }
+ break;
+ }
+ case ModelIndexer::QueuedFile::DIAGRAM_FILE:
+ {
+ bool scanFile = false;
+ IndexedDiagramReference *indexedDiagramReference = m_indexer->d->indexedDiagramReferences.value(queuedFile.file());
+ if (!indexedDiagramReference) {
+ qCDebug(logger) << "create new indexed diagram reference";
+ indexedDiagramReference = new IndexedDiagramReference(
+ queuedFile.file(), queuedFile.lastModified());
+ indexedDiagramReference->addOwningProject(queuedFile.project());
+ m_indexer->d->indexedDiagramReferences.insert(
+ queuedFile.file(), indexedDiagramReference);
+ scanFile = true;
+ } else if (queuedFile.lastModified() > indexedDiagramReference->lastModified()) {
+ qCDebug(logger) << "update indexed diagram reference";
+ indexedDiagramReference->addOwningProject(queuedFile.project());
+ indexedDiagramReference->reset(queuedFile.lastModified());
+ scanFile = true;
+ }
+ if (scanFile) {
+ locker.unlock();
+ // load diagram reference file
+ qmt::DiagramReferenceSerializer diagramReferenceSerializer;
+ qmt::DiagramReferenceSerializer::Reference reference = diagramReferenceSerializer.load(queuedFile.file());
+ locker.relock();
+ indexedDiagramReference->setModelUid(reference._model_uid);
+ indexedDiagramReference->setDiagramUid(reference._diagram_uid);
+ // add indexedDiagram_reference to set of indexedDiagramRefrerencesByUid
+ QSet<IndexedDiagramReference *> indexedDiagramReferences = m_indexer->d->indexedDiagramReferencesByDiagramUid.value(reference._diagram_uid);
+ indexedDiagramReferences.insert(indexedDiagramReference);
+ m_indexer->d->indexedDiagramReferencesByDiagramUid.insert(reference._diagram_uid, indexedDiagramReferences);
+ }
+ break;
+ }
+ }
+ }
+}
+
+ModelIndexer::ModelIndexer(QObject *parent)
+ : QObject(parent),
+ d(new ModelIndexerPrivate())
+{
+ d->indexerThread = new IndexerThread(this);
+ connect(this, &ModelIndexer::quitIndexerThread,
+ d->indexerThread, &ModelIndexer::IndexerThread::onQuitIndexerThread);
+ connect(this, &ModelIndexer::filesQueued,
+ d->indexerThread, &ModelIndexer::IndexerThread::onFilesQueued);
+ d->indexerThread->start();
+ connect(ProjectExplorer::SessionManager::instance(), &ProjectExplorer::SessionManager::projectAdded,
+ this, &ModelIndexer::onProjectAdded);
+ connect(ProjectExplorer::SessionManager::instance(), &ProjectExplorer::SessionManager::aboutToRemoveProject,
+ this, &ModelIndexer::onAboutToRemoveProject);
+}
+
+ModelIndexer::~ModelIndexer()
+{
+ emit quitIndexerThread();
+ d->indexerThread->wait();
+ delete d;
+}
+
+QString ModelIndexer::findModel(const qmt::Uid &modelUid)
+{
+ QMutexLocker locker(&d->indexerMutex);
+ QSet<IndexedModel *> indexedModels = d->indexedModelsByUid.value(modelUid);
+ if (indexedModels.isEmpty())
+ return QString();
+ IndexedModel *indexedModel = *indexedModels.cbegin();
+ QTC_ASSERT(indexedModel, return QString());
+ return indexedModel->file();
+}
+
+QString ModelIndexer::findDiagram(const qmt::Uid &modelUid, const qmt::Uid &diagramUid)
+{
+ Q_UNUSED(modelUid); // avoid warning in release mode
+
+ QMutexLocker locker(&d->indexerMutex);
+ QSet<IndexedDiagramReference *> indexedDiagramReferences = d->indexedDiagramReferencesByDiagramUid.value(diagramUid);
+ if (indexedDiagramReferences.isEmpty())
+ return QString();
+ IndexedDiagramReference *indexedDiagramReference = *indexedDiagramReferences.cbegin();
+ QTC_ASSERT(indexedDiagramReference, return QString());
+ QTC_ASSERT(indexedDiagramReference->modelUid() == modelUid, return QString());
+ return indexedDiagramReference->file();
+}
+
+void ModelIndexer::onProjectAdded(ProjectExplorer::Project *project)
+{
+ connect(project, &ProjectExplorer::Project::fileListChanged,
+ this, [=]() { this->onProjectFileListChanged(project); });
+ scanProject(project);
+}
+
+void ModelIndexer::onAboutToRemoveProject(ProjectExplorer::Project *project)
+{
+ disconnect(project, &ProjectExplorer::Project::fileListChanged, this, 0);
+ forgetProject(project);
+}
+
+void ModelIndexer::onProjectFileListChanged(ProjectExplorer::Project *project)
+{
+ scanProject(project);
+}
+
+void ModelIndexer::scanProject(ProjectExplorer::Project *project)
+{
+ // TODO harmonize following code with findFirstModel()?
+ QStringList files = project->files(ProjectExplorer::Project::ExcludeGeneratedFiles);
+ QQueue<QueuedFile> filesQueue;
+ QSet<QueuedFile> filesSet;
+
+ foreach (const QString &file, files) {
+ QFileInfo fileInfo(file);
+ Utils::MimeType mimeType = Utils::MimeDatabase().mimeTypeForFile(fileInfo);
+ QueuedFile::FileType fileType = QueuedFile::UNKNOWN_FILE_TYPE;
+ if (mimeType.name() == QLatin1String(Constants::MIME_TYPE_MODEL))
+ fileType = QueuedFile::MODEL_FILE;
+ else if (mimeType.name() == QLatin1String(Constants::MIME_TYPE_DIAGRAM_REFERENCE))
+ fileType = QueuedFile::DIAGRAM_FILE;
+ if (fileType != QueuedFile::UNKNOWN_FILE_TYPE) {
+ QueuedFile queuedFile(file, project, fileType, fileInfo.lastModified());
+ filesQueue.append(queuedFile);
+ filesSet.insert(queuedFile);
+ }
+ }
+
+ QString defaultModelFile = findFirstModel(project->rootProjectNode());
+
+ bool filesAreQueued = false;
+ {
+ QMutexLocker locker(&d->indexerMutex);
+
+ // remove deleted files from queue
+ for (int i = 0; i < d->filesQueue.size();) {
+ if (d->filesQueue.at(i).project() == project) {
+ if (filesSet.contains(d->filesQueue.at(i))) {
+ ++i;
+ } else {
+ d->queuedFilesSet.remove(d->filesQueue.at(i));
+ d->filesQueue.removeAt(i);
+ }
+ }
+ }
+
+ // remove deleted files from indexed models
+ foreach (const QString &file, d->indexedModels.keys()) {
+ if (!filesSet.contains(QueuedFile(file, project)))
+ removeModelFile(file, project);
+ }
+
+ // remove deleted files from indexed diagrams
+ foreach (const QString &file, d->indexedDiagramReferences.keys()) {
+ if (!filesSet.contains(QueuedFile(file, project)))
+ removeDiagramReferenceFile(file, project);
+ }
+
+ // queue files
+ while (!filesQueue.isEmpty()) {
+ QueuedFile queuedFile = filesQueue.takeFirst();
+ if (!d->queuedFilesSet.contains(queuedFile)) {
+ QTC_CHECK(!d->filesQueue.contains(queuedFile));
+ d->filesQueue.append(queuedFile);
+ d->queuedFilesSet.insert(queuedFile);
+ filesAreQueued = true;
+ }
+ }
+
+ // auto-open model file only if project is already configured
+ if (!defaultModelFile.isEmpty() && !project->targets().isEmpty()) {
+ d->defaultModelFiles.insert(QueuedFile(defaultModelFile, project,
+ QueuedFile::MODEL_FILE, QDateTime()));
+ }
+ }
+
+ if (filesAreQueued)
+ emit filesQueued();
+}
+
+QString ModelIndexer::findFirstModel(ProjectExplorer::FolderNode *folderNode)
+{
+ foreach (ProjectExplorer::FileNode *fileNode, folderNode->fileNodes()) {
+ Utils::MimeType mimeType = Utils::MimeDatabase().mimeTypeForFile(
+ fileNode->path().toFileInfo());
+ if (mimeType.name() == QLatin1String(Constants::MIME_TYPE_MODEL))
+ return fileNode->path().toString();
+ }
+ foreach (ProjectExplorer::FolderNode *subFolderNode, folderNode->subFolderNodes()) {
+ QString modelFileName = findFirstModel(subFolderNode);
+ if (!modelFileName.isEmpty())
+ return modelFileName;
+ }
+ return QString();
+}
+
+void ModelIndexer::forgetProject(ProjectExplorer::Project *project)
+{
+ QStringList files = project->files(ProjectExplorer::Project::ExcludeGeneratedFiles);
+
+ QMutexLocker locker(&d->indexerMutex);
+ foreach (const QString &file, files) {
+ // remove file from queue
+ QueuedFile queuedFile(file, project);
+ if (d->queuedFilesSet.contains(queuedFile)) {
+ QTC_CHECK(d->filesQueue.contains(queuedFile));
+ d->filesQueue.removeOne(queuedFile);
+ QTC_CHECK(!d->filesQueue.contains(queuedFile));
+ d->queuedFilesSet.remove(queuedFile);
+ }
+ removeModelFile(file, project);
+ removeDiagramReferenceFile(file, project);
+ }
+}
+
+void ModelIndexer::removeModelFile(const QString &file, ProjectExplorer::Project *project)
+{
+ IndexedModel *indexedModel = d->indexedModels.value(file);
+ if (indexedModel && indexedModel->owningProjects().contains(project)) {
+ qCDebug(logger) << "remove model file " << file
+ << " from project " << project->displayName();
+ indexedModel->removeOwningProject(project);
+ if (indexedModel->owningProjects().isEmpty()) {
+ qCDebug(logger) << "delete indexed model " << project->displayName();
+ d->indexedModels.remove(file);
+
+ // remove indexedModel from set of indexedModelsByUid
+ QTC_CHECK(d->indexedModelsByUid.contains(indexedModel->modelUid()));
+ QSet<IndexedModel *> indexedModels = d->indexedModelsByUid.value(indexedModel->modelUid());
+ QTC_CHECK(indexedModels.contains(indexedModel));
+ indexedModels.remove(indexedModel);
+ if (indexedModels.isEmpty())
+ d->indexedModelsByUid.remove(indexedModel->modelUid());
+ else
+ d->indexedModelsByUid.insert(indexedModel->modelUid(), indexedModels);
+
+ delete indexedModel;
+ }
+ }
+}
+
+void ModelIndexer::removeDiagramReferenceFile(const QString &file,
+ ProjectExplorer::Project *project)
+{
+ IndexedDiagramReference *indexedDiagramReference = d->indexedDiagramReferences.value(file);
+ if (indexedDiagramReference) {
+ QTC_CHECK(indexedDiagramReference->owningProjects().contains(project));
+ qCDebug(logger) << "remove diagram reference file "
+ << file << " from project " << project->displayName();
+ indexedDiagramReference->removeOwningProject(project);
+ if (indexedDiagramReference->owningProjects().isEmpty()) {
+ qCDebug(logger) << "delete indexed diagram reference from " << file;
+ d->indexedDiagramReferences.remove(file);
+
+ // remove indexedDiagramReference from set of indexedDiagramReferecesByDiagramUid
+ QTC_CHECK(d->indexedDiagramReferencesByDiagramUid.contains(indexedDiagramReference->diagramUid()));
+ QSet<IndexedDiagramReference *> indexedDiagramReferences = d->indexedDiagramReferencesByDiagramUid.value(indexedDiagramReference->diagramUid());
+ QTC_CHECK(indexedDiagramReferences.contains(indexedDiagramReference));
+ indexedDiagramReferences.remove(indexedDiagramReference);
+ if (indexedDiagramReferences.isEmpty()) {
+ d->indexedDiagramReferencesByDiagramUid.remove(
+ indexedDiagramReference->diagramUid());
+ } else {
+ d->indexedDiagramReferencesByDiagramUid.insert(
+ indexedDiagramReference->diagramUid(), indexedDiagramReferences);
+ }
+
+ delete indexedDiagramReference;
+ }
+ }
+}
+
+const QLoggingCategory &ModelIndexer::logger()
+{
+ static const QLoggingCategory category("qtc.modeleditor.modelindexer");
+ return category;
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/modelindexer.h b/src/plugins/modeleditor/modelindexer.h
new file mode 100644
index 00000000000..7d2e49b9596
--- /dev/null
+++ b/src/plugins/modeleditor/modelindexer.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef MODELINDEXER_H
+#define MODELINDEXER_H
+
+#include <QObject>
+
+namespace qmt { class Uid; }
+
+namespace ProjectExplorer {
+class Project;
+class FolderNode;
+}
+
+namespace ModelEditor {
+namespace Internal {
+
+class ModelIndexer :
+ public QObject
+{
+ Q_OBJECT
+ class QueuedFile;
+ class IndexedModel;
+ class IndexedDiagramReference;
+ class IndexerThread;
+ class DiagramsCollectorVisitor;
+ class ModelIndexerPrivate;
+
+ friend uint qHash(const ModelIndexer::QueuedFile &queued_file);
+ friend bool operator==(const ModelIndexer::QueuedFile &lhs,
+ const ModelIndexer::QueuedFile &rhs);
+
+public:
+ ModelIndexer(QObject *parent = 0);
+ ~ModelIndexer();
+
+signals:
+ void quitIndexerThread();
+ void filesQueued();
+ void openDefaultModel(const qmt::Uid &model_uid);
+
+public:
+ QString findModel(const qmt::Uid &modelUid);
+ QString findDiagram(const qmt::Uid &modelUid, const qmt::Uid &diagramUid);
+
+private slots:
+ void onProjectAdded(ProjectExplorer::Project *project);
+ void onAboutToRemoveProject(ProjectExplorer::Project *project);
+ void onProjectFileListChanged(ProjectExplorer::Project *project);
+
+private:
+ void scanProject(ProjectExplorer::Project *project);
+ QString findFirstModel(ProjectExplorer::FolderNode *folderNode);
+ void forgetProject(ProjectExplorer::Project *project);
+ void removeModelFile(const QString &file, ProjectExplorer::Project *project);
+ void removeDiagramReferenceFile(const QString &file, ProjectExplorer::Project *project);
+
+ static const QLoggingCategory &logger();
+
+private:
+ ModelIndexerPrivate *d;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // MODELINDEXER_H
diff --git a/src/plugins/modeleditor/modelsmanager.cpp b/src/plugins/modeleditor/modelsmanager.cpp
new file mode 100644
index 00000000000..37c6dbddc49
--- /dev/null
+++ b/src/plugins/modeleditor/modelsmanager.cpp
@@ -0,0 +1,465 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "modelsmanager.h"
+
+#include "diagramsviewmanager.h"
+#include "modeldocument.h"
+#include "diagramdocument.h"
+#include "diagrameditor.h"
+#include "extdocumentcontroller.h"
+#include "modelindexer.h"
+#include "pxnodecontroller.h"
+#include "modeleditor_constants.h"
+
+#include "qmt/config/configcontroller.h"
+#include "qmt/diagram_scene/diagramscenemodel.h"
+#include "qmt/diagram_ui/diagramsmanager.h"
+#include "qmt/model/mdiagram.h"
+#include "qmt/model_controller/modelcontroller.h"
+#include "qmt/project_controller/projectcontroller.h"
+#include "qmt/project/project.h"
+#include "qmt/serializer/diagramreferenceserializer.h"
+#include "qmt/stereotype/stereotypecontroller.h"
+#include "qmt/tasks/diagramscenecontroller.h"
+
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/editormanager/ieditor.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/actionmanager/actioncontainer.h>
+#include <coreplugin/icore.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/project.h>
+#include <projectexplorer/projectnodes.h>
+#include <projectexplorer/projecttree.h>
+#include <utils/fileutils.h>
+
+#include <QFileInfo>
+#include <QDir>
+#include <QTimer>
+#include <QAction>
+
+namespace ModelEditor {
+namespace Internal {
+
+class ModelsManager::ManagedModel
+{
+public:
+ ManagedModel() = default;
+ ManagedModel(ExtDocumentController *m_documentController,
+ DiagramsViewManager *m_diagramsViewManager, ModelDocument *m_modelDocument);
+
+ int m_counter = 0;
+ ExtDocumentController *m_documentController = 0;
+ DiagramsViewManager *m_diagramsViewManager = 0;
+ ModelDocument *m_modelDocument = 0;
+ QList<DiagramDocument *> m_diagramDocuments;
+};
+
+ModelsManager::ManagedModel::ManagedModel(ExtDocumentController *documentController,
+ DiagramsViewManager *diagramsViewManager,
+ ModelDocument *modelDocument)
+ : m_counter(1),
+ m_documentController(documentController),
+ m_diagramsViewManager(diagramsViewManager),
+ m_modelDocument(modelDocument)
+{
+}
+
+class ModelsManager::ModelsManagerPrivate
+{
+public:
+ ~ModelsManagerPrivate()
+ {
+ }
+
+ QList<ModelsManager::ManagedModel> managedModels;
+ ModelIndexer *modelIndexer = 0;
+ QList<Core::IDocument *> documentsToBeClosed;
+
+ QAction *openDiagramContextMenuItem = 0;
+ ProjectExplorer::Node *contextMenuOwnerNode = 0;
+};
+
+ModelsManager::ModelsManager(QObject *parent)
+ : QObject(parent),
+ d(new ModelsManagerPrivate())
+{
+ d->modelIndexer = new ModelIndexer(this);
+#ifdef OPEN_DEFAULT_MODEL // disable feature - needs setting; does not work with qbs
+ connect(d->modelIndexer, &ModelIndexer::openDefaultModel,
+ this, &ModelsManager::onOpenDefaultModel, Qt::QueuedConnection);
+#endif
+
+ Core::Context projecTreeContext(ProjectExplorer::Constants::C_PROJECT_TREE);
+ Core::ActionContainer *folderContainer = Core::ActionManager::actionContainer(
+ ProjectExplorer::Constants::M_FOLDERCONTEXT);
+ folderContainer->insertGroup(ProjectExplorer::Constants::G_FOLDER_FILES,
+ Constants::EXPLORER_GROUP_MODELING);
+ d->openDiagramContextMenuItem = new QAction(tr("Open Diagram"), this);
+ Core::Command *cmd = Core::ActionManager::registerAction(
+ d->openDiagramContextMenuItem, Constants::ACTION_EXPLORER_OPEN_DIAGRAM,
+ projecTreeContext);
+ folderContainer->addAction(cmd, Constants::EXPLORER_GROUP_MODELING);
+ connect(d->openDiagramContextMenuItem, &QAction::triggered,
+ this, &ModelsManager::onOpenDiagram);
+ connect(ProjectExplorer::ProjectTree::instance(), &ProjectExplorer::ProjectTree::aboutToShowContextMenu,
+ this, &ModelsManager::onAboutToShowContextMenu);
+}
+
+ModelsManager::~ModelsManager()
+{
+ QTC_CHECK(d->managedModels.isEmpty());
+ delete d;
+}
+
+bool ModelsManager::isDiagramOpen(const qmt::Uid &modelUid, const qmt::Uid &diagramUid) const
+{
+ foreach (const ManagedModel &managedModel, d->managedModels) {
+ if (managedModel.m_documentController->getProjectController()->getProject()->getUid() == modelUid) {
+ foreach (const DiagramDocument *diagramDocument, managedModel.m_diagramDocuments) {
+ if (diagramDocument->diagramUid() == diagramUid)
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+ExtDocumentController *ModelsManager::createModel(ModelDocument *modelDocument)
+{
+ auto documentController = new ExtDocumentController(this);
+ QDir dir;
+ dir.setPath(Core::ICore::resourcePath() + QLatin1String("/modeleditor"));
+ // TODO error output on reading definition files
+ documentController->getConfigController()->readStereotypeDefinitions(dir.path());
+
+ auto diagramsViewManager = new DiagramsViewManager(this);
+ connect(diagramsViewManager, &DiagramsViewManager::someDiagramOpened,
+ documentController->getDiagramsManager(), &qmt::DiagramsManager::someDiagramOpened);
+ connect(diagramsViewManager, &DiagramsViewManager::openEditor,
+ this, [=](const qmt::MDiagram *diagram) { this->onOpenEditor(documentController, diagram); });
+ connect(diagramsViewManager, &DiagramsViewManager::closeEditor,
+ this, [=](const qmt::MDiagram *diagram) { this->onCloseEditor(documentController, diagram); });
+ connect(diagramsViewManager, &DiagramsViewManager::diagramRenamed,
+ this, [=](const qmt::MDiagram *diagram) { this->onDiagramRenamed(documentController, diagram); });
+ d->managedModels.append(ManagedModel(documentController, diagramsViewManager, modelDocument));
+ return documentController;
+}
+
+ExtDocumentController *ModelsManager::findModelByFileName(const QString &fileName,
+ ModelDocument *modelDocument)
+{
+ Utils::FileName fileName1 = Utils::FileName::fromString(fileName);
+ for (int i = 0; i < d->managedModels.size(); ++i) {
+ ManagedModel *managedModel = &d->managedModels[i];
+ Utils::FileName fileName2 = Utils::FileName::fromString(managedModel->m_documentController->getProjectController()->getProject()->getFileName());
+ if (fileName1 == fileName2) {
+ if (managedModel->m_modelDocument != modelDocument) {
+ QTC_CHECK(!managedModel->m_modelDocument);
+ managedModel->m_modelDocument = modelDocument;
+ ++managedModel->m_counter;
+ }
+ return managedModel->m_documentController;
+ }
+ }
+ return 0;
+}
+
+ExtDocumentController *ModelsManager::findOrLoadModel(const qmt::Uid &modelUid,
+ DiagramDocument *diagramDocument)
+{
+ for (int i = 0; i < d->managedModels.size(); ++i) {
+ ManagedModel *managedModel = &d->managedModels[i];
+ if (managedModel->m_documentController->getProjectController()->getProject()->getUid() == modelUid) {
+ ++managedModel->m_counter;
+ QTC_CHECK(!managedModel->m_diagramDocuments.contains(diagramDocument));
+ managedModel->m_diagramDocuments.append(diagramDocument);
+ return managedModel->m_documentController;
+ }
+ }
+
+ QString modelFile = d->modelIndexer->findModel(modelUid);
+ if (modelFile.isEmpty())
+ return 0;
+ qmt::DocumentController *documentController = createModel(0);
+ documentController->loadProject(modelFile);
+
+ for (int i = 0; i < d->managedModels.size(); ++i) {
+ ManagedModel *managedModel = &d->managedModels[i];
+ if (managedModel->m_documentController->getProjectController()->getProject()->getUid() == modelUid) {
+ // the counter was already set to 1 in createModel(0)
+ QTC_CHECK(managedModel->m_counter == 1);
+ QTC_CHECK(!managedModel->m_diagramDocuments.contains(diagramDocument));
+ managedModel->m_diagramDocuments.append(diagramDocument);
+ return managedModel->m_documentController;
+ }
+ }
+
+ QTC_ASSERT(false, return 0);
+ return 0;
+}
+
+void ModelsManager::release(ExtDocumentController *documentController, ModelDocument *modelDocument)
+{
+ Q_UNUSED(modelDocument); // avoid warning in release mode
+
+ for (int i = 0; i < d->managedModels.size(); ++i) {
+ ManagedModel *managedModel = &d->managedModels[i];
+ if (managedModel->m_documentController == documentController) {
+ QTC_CHECK(managedModel->m_counter > 0);
+ --managedModel->m_counter;
+ QTC_CHECK(managedModel->m_modelDocument == modelDocument);
+ managedModel->m_modelDocument = 0;
+ if (!managedModel->m_counter) {
+ delete managedModel->m_diagramsViewManager;
+ delete managedModel->m_documentController;
+ d->managedModels.removeAt(i);
+ }
+ return;
+ }
+ }
+ QTC_CHECK(false);
+}
+
+void ModelsManager::release(ExtDocumentController *documentController,
+ DiagramDocument *diagramDocument)
+{
+ for (int i = 0; i < d->managedModels.size(); ++i) {
+ ManagedModel *managedModel = &d->managedModels[i];
+ if (managedModel->m_documentController == documentController) {
+ QTC_CHECK(managedModel->m_counter > 0);
+ --managedModel->m_counter;
+ QTC_CHECK(managedModel->m_diagramDocuments.contains(diagramDocument));
+ managedModel->m_diagramDocuments.removeOne(diagramDocument);
+ if (!managedModel->m_counter) {
+ delete managedModel->m_diagramsViewManager;
+ delete managedModel->m_documentController;
+ d->managedModels.removeAt(i);
+ }
+ return;
+ }
+ }
+ QTC_CHECK(false);
+}
+
+DiagramsViewManager *ModelsManager::findDiagramsViewManager(
+ ExtDocumentController *documentController) const
+{
+ foreach (const ManagedModel &managedModel, d->managedModels) {
+ if (managedModel.m_documentController == documentController)
+ return managedModel.m_diagramsViewManager;
+ }
+ QTC_CHECK(false);
+ return 0;
+}
+
+ModelDocument *ModelsManager::findModelDocument(
+ ExtDocumentController *documentController) const
+{
+ foreach (const ManagedModel &managedModel, d->managedModels) {
+ if (managedModel.m_documentController == documentController)
+ return managedModel.m_modelDocument;
+ }
+ QTC_CHECK(false);
+ return 0;
+}
+
+QList<ExtDocumentController *> ModelsManager::collectAllDocumentControllers() const
+{
+ QList<ExtDocumentController *> documents;
+ foreach (const ManagedModel &managedModel, d->managedModels) {
+ QTC_ASSERT(managedModel.m_documentController, continue);
+ documents.append(managedModel.m_documentController);
+ }
+ return documents;
+}
+
+void ModelsManager::openDiagram(const qmt::Uid &modelUid, const qmt::Uid &diagramUid)
+{
+ foreach (const ManagedModel &managedModel, d->managedModels) {
+ if (managedModel.m_documentController->getProjectController()->getProject()->getUid() == modelUid) {
+ qmt::MDiagram *diagram = managedModel.m_documentController->getModelController()->findObject<qmt::MDiagram>(diagramUid);
+ QTC_ASSERT(diagram, continue);
+ onOpenEditor(managedModel.m_documentController, diagram);
+ }
+ }
+}
+
+void ModelsManager::onOpenEditor(ExtDocumentController *documentController,
+ const qmt::MDiagram *diagram)
+{
+ foreach (const ManagedModel &managedModel, d->managedModels) {
+ if (managedModel.m_documentController == documentController) {
+ if (managedModel.m_modelDocument
+ && managedModel.m_modelDocument->diagramUid() == diagram->getUid()) {
+ Core::EditorManager::activateEditorForDocument(managedModel.m_modelDocument);
+ return;
+ } else {
+ foreach (DiagramDocument *diagramDocument, managedModel.m_diagramDocuments) {
+ if (diagramDocument->diagramUid() == diagram->getUid()) {
+ Core::EditorManager::activateEditorForDocument(diagramDocument);
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ // if diagram is root diagram open model file editor
+ if (diagram == documentController->findRootDiagram()) {
+ foreach (const ManagedModel &managedModel, d->managedModels) {
+ if (managedModel.m_documentController == documentController) {
+ QTC_CHECK(!managedModel.m_modelDocument);
+ Core::EditorManager::openEditor(documentController->getProjectController()->getProject()->getFileName());
+ return;
+ }
+ }
+ QTC_CHECK(false);
+ }
+
+ // search diagram in model index and open that file
+ QString documentReferenceFile =
+ d->modelIndexer->findDiagram(
+ documentController->getProjectController()->getProject()->getUid(),
+ diagram->getUid());
+ if (!documentReferenceFile.isEmpty()) {
+ Core::EditorManager::openEditor(documentReferenceFile);
+ } else {
+ // open new temporary diagram editor
+ qmt::DiagramReferenceSerializer serializer;
+ QByteArray contents = serializer.save(
+ documentController->getProjectController()->getProject(), diagram);
+ Core::IEditor *editor = Core::EditorManager::openEditorWithContents(
+ Core::Id(Constants::DIAGRAM_EDITOR_ID), 0, contents);
+ // bring editor to front
+ Core::EditorManager::activateEditor(editor);
+ }
+}
+
+void ModelsManager::onCloseEditor(ExtDocumentController *documentController,
+ const qmt::MDiagram *diagram)
+{
+ bool closeDocument = false;
+ foreach (const ManagedModel &managedModel, d->managedModels) {
+ if (managedModel.m_documentController == documentController) {
+ if (managedModel.m_modelDocument
+ && managedModel.m_modelDocument->diagramUid() == diagram->getUid()) {
+ d->documentsToBeClosed.append(managedModel.m_modelDocument);
+ closeDocument = true;
+ } else {
+ foreach (DiagramDocument *diagramDocument, managedModel.m_diagramDocuments) {
+ if (diagramDocument->diagramUid() == diagram->getUid()) {
+ d->documentsToBeClosed.append(diagramDocument);
+ closeDocument = true;
+ }
+ }
+ }
+ }
+ }
+ if (closeDocument) {
+ // TODO remove this or fix asynchronous call
+ // Closing documents later one must garuantee that no remaining events are executed
+ // maybe by using some deleteLater() trick? (create and deleteLater a QObject that
+ // will call onCloseDocumentsLater())
+ //QTimer::singleShot(0, this, SLOT(onCloseDocumentsLater()));
+ onCloseDocumentsLater();
+ }
+}
+
+void ModelsManager::onCloseDocumentsLater()
+{
+ QList<Core::IDocument *> documents = d->documentsToBeClosed;
+ d->documentsToBeClosed.clear();
+ Core::EditorManager::closeDocuments(documents);
+}
+
+void ModelsManager::onDiagramRenamed(ExtDocumentController *documentController,
+ const qmt::MDiagram *diagram)
+{
+ foreach (const ManagedModel &managedModel, d->managedModels) {
+ if (managedModel.m_documentController == documentController) {
+ if (managedModel.m_modelDocument
+ && managedModel.m_modelDocument->diagramUid() == diagram->getUid()) {
+ managedModel.m_modelDocument->onDiagramRenamed();
+ } else {
+ foreach (DiagramDocument *diagramDocument, managedModel.m_diagramDocuments) {
+ if (diagramDocument->diagramUid() == diagram->getUid())
+ diagramDocument->onDiagramRenamed();
+ }
+ }
+ }
+ }
+}
+
+void ModelsManager::onAboutToShowContextMenu(ProjectExplorer::Project *project,
+ ProjectExplorer::Node *node)
+{
+ Q_UNUSED(project);
+
+ bool canOpenDiagram = false;
+
+ foreach (const ManagedModel &managedModel, d->managedModels) {
+ if (managedModel.m_documentController->pxNodeController()->hasDiagramForExplorerNode(node)) {
+ canOpenDiagram = true;
+ break;
+ }
+ }
+
+ if (canOpenDiagram)
+ d->contextMenuOwnerNode = node;
+ else
+ d->contextMenuOwnerNode = 0;
+ d->openDiagramContextMenuItem->setVisible(canOpenDiagram);
+}
+
+void ModelsManager::onOpenDiagram()
+{
+ if (ProjectExplorer::ProjectTree::instance()->currentNode() == d->contextMenuOwnerNode) {
+ qmt::MDiagram *diagram = 0;
+ foreach (const ManagedModel &managedModel, d->managedModels) {
+ if ((diagram = managedModel.m_documentController->pxNodeController()->findDiagramForExplorerNode(d->contextMenuOwnerNode))) {
+ onOpenEditor(managedModel.m_documentController, diagram);
+ break;
+ }
+ }
+ }
+}
+
+void ModelsManager::onOpenDefaultModel(const qmt::Uid &modelUid)
+{
+ QString modelFile = d->modelIndexer->findModel(modelUid);
+ if (!modelFile.isEmpty())
+ Core::EditorManager::openEditor(modelFile);
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/modelsmanager.h b/src/plugins/modeleditor/modelsmanager.h
new file mode 100644
index 00000000000..26c2854c6e1
--- /dev/null
+++ b/src/plugins/modeleditor/modelsmanager.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef MODELSMANAGER_H
+#define MODELSMANAGER_H
+
+#include <QObject>
+
+namespace ProjectExplorer {
+class Project;
+class Node;
+}
+
+namespace qmt {
+class Uid;
+class MDiagram;
+}
+
+namespace ModelEditor {
+namespace Internal {
+
+class ExtDocumentController;
+class DiagramsViewManager;
+class ModelDocument;
+class DiagramDocument;
+
+class ModelsManager :
+ public QObject
+{
+ Q_OBJECT
+ class ManagedModel;
+ class ModelsManagerPrivate;
+
+public:
+ explicit ModelsManager(QObject *parent = 0);
+ ~ModelsManager();
+
+ bool isDiagramOpen(const qmt::Uid &modelUid, const qmt::Uid &diagramUid) const;
+
+ ExtDocumentController *createModel(ModelDocument *findModelDocument);
+ ExtDocumentController *findModelByFileName(const QString &fileName,
+ ModelDocument *findModelDocument);
+ ExtDocumentController *findOrLoadModel(const qmt::Uid &modelUid,
+ DiagramDocument *diagramDocument);
+ void release(ExtDocumentController *documentController, ModelDocument *findModelDocument);
+ void release(ExtDocumentController *documentController, DiagramDocument *diagramDocument);
+ DiagramsViewManager *findDiagramsViewManager(ExtDocumentController *documentController) const;
+ ModelDocument *findModelDocument(ExtDocumentController *documentController) const;
+ QList<ExtDocumentController *> collectAllDocumentControllers() const;
+ void openDiagram(const qmt::Uid &modelUid, const qmt::Uid &diagramUid);
+
+private slots:
+ void onOpenEditor(ExtDocumentController *documentController, const qmt::MDiagram *diagram);
+ void onCloseEditor(ExtDocumentController *documentController, const qmt::MDiagram *diagram);
+ void onCloseDocumentsLater();
+ void onDiagramRenamed(ExtDocumentController *documentController, const qmt::MDiagram *diagram);
+ void onAboutToShowContextMenu(ProjectExplorer::Project *project, ProjectExplorer::Node *node);
+ void onOpenDiagram();
+ void onOpenDefaultModel(const qmt::Uid &modelUid);
+
+private:
+ ModelsManagerPrivate *d;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // MODELSMANAGER_H
diff --git a/src/plugins/modeleditor/openelementvisitor.cpp b/src/plugins/modeleditor/openelementvisitor.cpp
new file mode 100644
index 00000000000..33b8e7362a9
--- /dev/null
+++ b/src/plugins/modeleditor/openelementvisitor.cpp
@@ -0,0 +1,208 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "openelementvisitor.h"
+
+#include "elementtasks.h"
+
+#include "qmt/diagram/dobject.h"
+#include "qmt/diagram/dpackage.h"
+#include "qmt/diagram/dclass.h"
+#include "qmt/diagram/dcomponent.h"
+#include "qmt/diagram/ddiagram.h"
+#include "qmt/diagram/ditem.h"
+#include "qmt/diagram/drelation.h"
+#include "qmt/diagram/ddependency.h"
+#include "qmt/diagram/dinheritance.h"
+#include "qmt/diagram/dassociation.h"
+
+#include "qmt/model/melement.h"
+#include "qmt/model/mpackage.h"
+#include "qmt/model/mclass.h"
+#include "qmt/model/mcomponent.h"
+#include "qmt/model/mdiagram.h"
+#include "qmt/model/mcanvasdiagram.h"
+#include "qmt/model/mitem.h"
+
+#include "qmt/model_controller/modelcontroller.h"
+
+namespace ModelEditor {
+namespace Internal {
+
+void OpenDiagramElementVisitor::setModelController(qmt::ModelController *modelController)
+{
+ m_modelController = modelController;
+}
+
+void OpenDiagramElementVisitor::setElementTasks(ElementTasks *elementTasks)
+{
+ m_elementTasks = elementTasks;
+}
+
+void OpenDiagramElementVisitor::visitDElement(const qmt::DElement *element)
+{
+ qmt::MElement *modelElement = m_modelController->findElement(element->getModelUid());
+ if (modelElement) {
+ OpenModelElementVisitor visitor;
+ visitor.setElementTasks(m_elementTasks);
+ modelElement->accept(&visitor);
+ }
+}
+
+void OpenDiagramElementVisitor::visitDObject(const qmt::DObject *object)
+{
+ visitDElement(object);
+}
+
+void OpenDiagramElementVisitor::visitDPackage(const qmt::DPackage *package)
+{
+ visitDObject(package);
+}
+
+void OpenDiagramElementVisitor::visitDClass(const qmt::DClass *klass)
+{
+ visitDObject(klass);
+}
+
+void OpenDiagramElementVisitor::visitDComponent(const qmt::DComponent *component)
+{
+ visitDObject(component);
+}
+
+void OpenDiagramElementVisitor::visitDDiagram(const qmt::DDiagram *diagram)
+{
+ visitDObject(diagram);
+}
+
+void OpenDiagramElementVisitor::visitDItem(const qmt::DItem *item)
+{
+ visitDObject(item);
+}
+
+void OpenDiagramElementVisitor::visitDRelation(const qmt::DRelation *relation)
+{
+ visitDElement(relation);
+}
+
+void OpenDiagramElementVisitor::visitDInheritance(const qmt::DInheritance *inheritance)
+{
+ visitDRelation(inheritance);
+}
+
+void OpenDiagramElementVisitor::visitDDependency(const qmt::DDependency *dependency)
+{
+ visitDRelation(dependency);
+}
+
+void OpenDiagramElementVisitor::visitDAssociation(const qmt::DAssociation *association)
+{
+ visitDRelation(association);
+}
+
+void OpenDiagramElementVisitor::visitDAnnotation(const qmt::DAnnotation *annotation)
+{
+ Q_UNUSED(annotation);
+}
+
+void OpenDiagramElementVisitor::visitDBoundary(const qmt::DBoundary *boundary)
+{
+ Q_UNUSED(boundary);
+}
+
+void OpenModelElementVisitor::setElementTasks(ElementTasks *elementTasks)
+{
+ m_elementTasks = elementTasks;
+}
+
+void OpenModelElementVisitor::visitMElement(const qmt::MElement *element)
+{
+ Q_UNUSED(element);
+}
+
+void OpenModelElementVisitor::visitMObject(const qmt::MObject *object)
+{
+ Q_UNUSED(object);
+}
+
+void OpenModelElementVisitor::visitMPackage(const qmt::MPackage *package)
+{
+ if (m_elementTasks->hasDiagram(package))
+ m_elementTasks->openDiagram(package);
+ else if (m_elementTasks->mayCreateDiagram(package))
+ m_elementTasks->createAndOpenDiagram(package);
+}
+
+void OpenModelElementVisitor::visitMClass(const qmt::MClass *klass)
+{
+ m_elementTasks->openClassDefinition(klass);
+}
+
+void OpenModelElementVisitor::visitMComponent(const qmt::MComponent *component)
+{
+ m_elementTasks->openSourceFile(component);
+}
+
+void OpenModelElementVisitor::visitMDiagram(const qmt::MDiagram *diagram)
+{
+ m_elementTasks->openDiagram(diagram);
+}
+
+void OpenModelElementVisitor::visitMCanvasDiagram(const qmt::MCanvasDiagram *diagram)
+{
+ visitMDiagram(diagram);
+}
+
+void OpenModelElementVisitor::visitMItem(const qmt::MItem *item)
+{
+ visitMObject(item);
+}
+
+void OpenModelElementVisitor::visitMRelation(const qmt::MRelation *relation)
+{
+ Q_UNUSED(relation);
+}
+
+void OpenModelElementVisitor::visitMDependency(const qmt::MDependency *dependency)
+{
+ Q_UNUSED(dependency);
+}
+
+void OpenModelElementVisitor::visitMInheritance(const qmt::MInheritance *inheritance)
+{
+ Q_UNUSED(inheritance);
+}
+
+void OpenModelElementVisitor::visitMAssociation(const qmt::MAssociation *association)
+{
+ Q_UNUSED(association);
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/openelementvisitor.h b/src/plugins/modeleditor/openelementvisitor.h
new file mode 100644
index 00000000000..7adbe2e11d1
--- /dev/null
+++ b/src/plugins/modeleditor/openelementvisitor.h
@@ -0,0 +1,96 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef OPENELEMENTVISITOR_H
+#define OPENELEMENTVISITOR_H
+
+#include "qmt/diagram/dconstvisitor.h"
+#include "qmt/model/mconstvisitor.h"
+
+namespace qmt { class ModelController; }
+
+namespace ModelEditor {
+namespace Internal {
+
+class ElementTasks;
+
+class OpenDiagramElementVisitor :
+ public qmt::DConstVisitor
+{
+public:
+ void setModelController(qmt::ModelController *modelController);
+ void setElementTasks(ElementTasks *elementTasks);
+
+ void visitDElement(const qmt::DElement *element);
+ void visitDObject(const qmt::DObject *object);
+ void visitDPackage(const qmt::DPackage *package);
+ void visitDClass(const qmt::DClass *klass);
+ void visitDComponent(const qmt::DComponent *component);
+ void visitDDiagram(const qmt::DDiagram *diagram);
+ void visitDItem(const qmt::DItem *item);
+ void visitDRelation(const qmt::DRelation *relation);
+ void visitDInheritance(const qmt::DInheritance *inheritance);
+ void visitDDependency(const qmt::DDependency *dependency);
+ void visitDAssociation(const qmt::DAssociation *association);
+ void visitDAnnotation(const qmt::DAnnotation *annotation);
+ void visitDBoundary(const qmt::DBoundary *boundary);
+
+private:
+ qmt::ModelController *m_modelController = 0;
+ ElementTasks *m_elementTasks = 0;
+};
+
+class OpenModelElementVisitor :
+ public qmt::MConstVisitor
+{
+public:
+ void setElementTasks(ElementTasks *elementTasks);
+
+ void visitMElement(const qmt::MElement *element) override;
+ void visitMObject(const qmt::MObject *object) override;
+ void visitMPackage(const qmt::MPackage *package) override;
+ void visitMClass(const qmt::MClass *klass) override;
+ void visitMComponent(const qmt::MComponent *component) override;
+ void visitMDiagram(const qmt::MDiagram *diagram) override;
+ void visitMCanvasDiagram(const qmt::MCanvasDiagram *diagram) override;
+ void visitMItem(const qmt::MItem *item) override;
+ void visitMRelation(const qmt::MRelation *relation) override;
+ void visitMDependency(const qmt::MDependency *dependency) override;
+ void visitMInheritance(const qmt::MInheritance *inheritance) override;
+ void visitMAssociation(const qmt::MAssociation *association) override;
+
+private:
+ ElementTasks *m_elementTasks = 0;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // OPENELEMENTVISITOR_H
diff --git a/src/plugins/modeleditor/pxnodecontroller.cpp b/src/plugins/modeleditor/pxnodecontroller.cpp
new file mode 100644
index 00000000000..8389af064f8
--- /dev/null
+++ b/src/plugins/modeleditor/pxnodecontroller.cpp
@@ -0,0 +1,389 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "pxnodecontroller.h"
+
+#include "pxnodeutilities.h"
+#include "componentviewcontroller.h"
+#include "classviewcontroller.h"
+
+#include "qmt/model/mpackage.h"
+#include "qmt/model/mclass.h"
+#include "qmt/model/mcomponent.h"
+#include "qmt/model/mdiagram.h"
+#include "qmt/model/mcanvasdiagram.h"
+#include "qmt/controller/namecontroller.h"
+#include "qmt/controller/undocontroller.h"
+#include "qmt/model_controller/modelcontroller.h"
+#include "qmt/tasks/diagramscenecontroller.h"
+
+#include <projectexplorer/projectnodes.h>
+#include <utils/qtcassert.h>
+
+#include <QAction>
+#include <QMenu>
+#include <QQueue>
+
+namespace ModelEditor {
+namespace Internal {
+
+class PxNodeController::MenuAction :
+ public QAction
+{
+public:
+ enum Type {
+ TYPE_ADD_COMPONENT,
+ TYPE_ADD_CLASS,
+ TYPE_ADD_PACKAGE,
+ TYPE_ADD_PACKAGE_AND_DIAGRAM,
+ TYPE_ADD_PACKAGE_MODEL,
+ TYPE_ADD_COMPONENT_MODEL,
+ TYPE_ADD_CLASS_MODEL
+ };
+
+public:
+ MenuAction(const QString &text, const QString &elementName, Type type, int index,
+ QObject *parent)
+ : QAction(text, parent),
+ elementName(elementName),
+ type(type),
+ index(index)
+ {
+ }
+
+ MenuAction(const QString &text, const QString &elementName, Type type, QObject *parent)
+ : QAction(text, parent),
+ elementName(elementName),
+ type(type),
+ index(-1)
+ {
+ }
+
+ QString elementName;
+ int type;
+ int index;
+ QString className;
+ QString packageStereotype;
+};
+
+class PxNodeController::PxNodeControllerPrivate
+{
+public:
+ PxNodeUtilities *pxnodeUtilities = 0;
+ ComponentViewController *componentViewController = 0;
+ ClassViewController *classViewController = 0;
+ qmt::DiagramSceneController *diagramSceneController = 0;
+ QString anchorFolder;
+};
+
+PxNodeController::PxNodeController(QObject *parent)
+ : QObject(parent),
+ d(new PxNodeControllerPrivate)
+{
+ d->pxnodeUtilities = new PxNodeUtilities(this);
+ d->componentViewController = new ComponentViewController(this);
+ d->componentViewController->setPxNodeUtilties(d->pxnodeUtilities);
+ d->classViewController = new ClassViewController(this);
+}
+
+PxNodeController::~PxNodeController()
+{
+ delete d;
+}
+
+void PxNodeController::setDiagramSceneController(
+ qmt::DiagramSceneController *diagramSceneController)
+{
+ d->diagramSceneController = diagramSceneController;
+ d->pxnodeUtilities->setDiagramSceneController(diagramSceneController);
+ d->componentViewController->setDiagramSceneController(diagramSceneController);
+}
+
+void PxNodeController::setAnchorFolder(const QString &anchorFolder)
+{
+ d->anchorFolder = anchorFolder;
+}
+
+void PxNodeController::addExplorerNode(const ProjectExplorer::Node *node,
+ qmt::DElement *topMostElementAtPos, const QPointF &pos,
+ qmt::MDiagram *diagram)
+{
+ QTC_ASSERT(node, return);
+ QTC_ASSERT(diagram, return);
+
+ QString elementName = qmt::NameController::convertFileNameToElementName(
+ node->path().toString());
+
+ switch (node->nodeType()) {
+ case ProjectExplorer::FileNodeType:
+ {
+ QStringList classNames = d->classViewController->findClassDeclarations(
+ node->path().toString()).toList();
+ auto menu = new QMenu;
+ menu->addAction(new MenuAction(tr("Add Component %1").arg(elementName), elementName,
+ MenuAction::TYPE_ADD_COMPONENT, menu));
+ menu->addSeparator();
+ int index = 0;
+ foreach (const QString &className, classNames) {
+ auto action = new MenuAction(tr("Add Class %1").arg(className), elementName,
+ MenuAction::TYPE_ADD_CLASS, index, menu);
+ action->className = className;
+ menu->addAction(action);
+ ++index;
+ }
+ connect(menu, &QMenu::aboutToHide, menu, &QMenu::deleteLater);
+ connect(menu, &QMenu::triggered, this, [=](QAction *action) {
+ // TODO potential risk if node, topMostElementAtPos or diagram is deleted in between
+ onMenuActionTriggered(static_cast<MenuAction *>(action), node, topMostElementAtPos,
+ pos, diagram);
+ });
+ menu->popup(QCursor::pos());
+ break;
+ }
+ case ProjectExplorer::FolderNodeType:
+ case ProjectExplorer::VirtualFolderNodeType:
+ case ProjectExplorer::ProjectNodeType:
+ {
+ QString stereotype;
+ switch (node->nodeType()) {
+ case ProjectExplorer::VirtualFolderNodeType:
+ stereotype = QStringLiteral("virtual folder");
+ break;
+ case ProjectExplorer::ProjectNodeType:
+ stereotype = QStringLiteral("project");
+ break;
+ default:
+ break;
+ }
+ auto menu = new QMenu;
+ auto action = new MenuAction(tr("Add Package %1").arg(elementName), elementName,
+ MenuAction::TYPE_ADD_PACKAGE, menu);
+ action->packageStereotype = stereotype;
+ menu->addAction(action);
+ action = new MenuAction(tr("Add Package and Diagram %1").arg(elementName), elementName,
+ MenuAction::TYPE_ADD_PACKAGE_AND_DIAGRAM, menu);
+ action->packageStereotype = stereotype;
+ menu->addAction(action);
+ action = new MenuAction(tr("Add Component Model"), elementName,
+ MenuAction::TYPE_ADD_COMPONENT_MODEL, menu);
+ action->packageStereotype = stereotype;
+ menu->addAction(action);
+ connect(menu, &QMenu::aboutToHide, menu, &QMenu::deleteLater);
+ connect(menu, &QMenu::triggered, this, [=](QAction *action) {
+ onMenuActionTriggered(static_cast<MenuAction *>(action), node, topMostElementAtPos,
+ pos, diagram);
+ });
+ menu->popup(QCursor::pos());
+ break;
+ }
+ case ProjectExplorer::SessionNodeType:
+ break;
+ }
+}
+
+bool PxNodeController::hasDiagramForExplorerNode(const ProjectExplorer::Node *node)
+{
+ return findDiagramForExplorerNode(node) != 0;
+}
+
+qmt::MDiagram *PxNodeController::findDiagramForExplorerNode(const ProjectExplorer::Node *node)
+{
+ QStringList relativeElements = qmt::NameController::buildElementsPath(
+ d->pxnodeUtilities->calcRelativePath(node, d->anchorFolder), false);
+
+ QQueue<qmt::MPackage *> roots;
+ roots.append(d->diagramSceneController->getModelController()->getRootPackage());
+
+ while (!roots.isEmpty()) {
+ qmt::MPackage *package = roots.takeFirst();
+
+ // append all sub-packages of the same level as next root packages
+ foreach (const qmt::Handle<qmt::MObject> &handle, package->getChildren()) {
+ if (handle.hasTarget()) {
+ if (auto childPackage = dynamic_cast<qmt::MPackage *>(handle.getTarget()))
+ roots.append(childPackage);
+ }
+ }
+
+ // goto into sub-packages to find complete chain of names
+ int relativeIndex = 0;
+ bool found = true;
+ while (found && relativeIndex < relativeElements.size()) {
+ QString relativeSearchId = qmt::NameController::calcElementNameSearchId(
+ relativeElements.at(relativeIndex));
+ found = false;
+ foreach (const qmt::Handle<qmt::MObject> &handle, package->getChildren()) {
+ if (handle.hasTarget()) {
+ if (auto childPackage = dynamic_cast<qmt::MPackage *>(handle.getTarget())) {
+ if (qmt::NameController::calcElementNameSearchId(childPackage->getName()) == relativeSearchId) {
+ package = childPackage;
+ ++relativeIndex;
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (found) {
+ QTC_ASSERT(relativeIndex >= relativeElements.size(), return 0);
+ // complete package chain found so check for appropriate diagram within deepest package
+ qmt::MDiagram *diagram = d->diagramSceneController->findDiagramBySearchId(
+ package, package->getName());
+ if (diagram)
+ return diagram;
+ // find first diagram within deepest package
+ foreach (const qmt::Handle<qmt::MObject> &handle, package->getChildren()) {
+ if (handle.hasTarget()) {
+ if (auto diagram = dynamic_cast<qmt::MDiagram *>(handle.getTarget()))
+ return diagram;
+ }
+ }
+ }
+ }
+
+ // complete sub-package structure scanned but did not found the desired object
+ return 0;
+}
+
+void PxNodeController::onMenuActionTriggered(PxNodeController::MenuAction *action,
+ const ProjectExplorer::Node *node,
+ qmt::DElement *topMostElementAtPos,
+ const QPointF &pos, qmt::MDiagram *diagram)
+{
+ qmt::MObject *newObject = 0;
+ qmt::MDiagram *newDiagramInObject = 0;
+
+ switch (action->type) {
+ case MenuAction::TYPE_ADD_COMPONENT:
+ {
+ auto component = new qmt::MComponent();
+ component->setFlags(qmt::MElement::REVERSE_ENGINEERED);
+ component->setName(action->elementName);
+ newObject = component;
+ break;
+ }
+ case MenuAction::TYPE_ADD_CLASS:
+ {
+ // TODO handle template classes
+ auto klass = new qmt::MClass();
+ klass->setFlags(qmt::MElement::REVERSE_ENGINEERED);
+ QString qualifiedName = action->className;
+ int i = qualifiedName.lastIndexOf(QStringLiteral("::"));
+ if (i >= 0) {
+ klass->setNamespace(qualifiedName.left(i));
+ klass->setName(qualifiedName.mid(i + 2));
+ } else {
+ klass->setName(qualifiedName);
+ }
+ newObject = klass;
+ break;
+ }
+ case MenuAction::TYPE_ADD_PACKAGE:
+ case MenuAction::TYPE_ADD_PACKAGE_AND_DIAGRAM:
+ {
+ auto package = new qmt::MPackage();
+ package->setFlags(qmt::MElement::REVERSE_ENGINEERED);
+ package->setName(action->elementName);
+ if (!action->packageStereotype.isEmpty())
+ package->setStereotypes(QStringList() << action->packageStereotype);
+ newObject = package;
+ if (action->type == MenuAction::TYPE_ADD_PACKAGE_AND_DIAGRAM) {
+ auto diagram = new qmt::MCanvasDiagram();
+ diagram->setName(action->elementName);
+ newDiagramInObject = diagram;
+ }
+ break;
+ }
+ case MenuAction::TYPE_ADD_COMPONENT_MODEL:
+ {
+ auto package = new qmt::MPackage();
+ package->setFlags(qmt::MElement::REVERSE_ENGINEERED);
+ package->setName(action->elementName);
+ if (!action->packageStereotype.isEmpty())
+ package->setStereotypes(QStringList() << action->packageStereotype);
+ auto folderNode = dynamic_cast<const ProjectExplorer::FolderNode *>(node);
+ QTC_CHECK(folderNode);
+ if (folderNode) {
+ d->diagramSceneController->getModelController()->getUndoController()->beginMergeSequence(tr("Create Component Model"));
+ QStringList relativeElements = qmt::NameController::buildElementsPath(
+ d->pxnodeUtilities->calcRelativePath(folderNode, d->anchorFolder), true);
+ if (qmt::MObject *existingObject = d->pxnodeUtilities->findSameObject(relativeElements, package)) {
+ delete package;
+ package = dynamic_cast<qmt::MPackage *>(existingObject);
+ QTC_ASSERT(package, return);
+ d->diagramSceneController->addExistingModelElement(package->getUid(), pos, diagram);
+ } else {
+ qmt::MPackage *requestedRootPackage = d->diagramSceneController->findSuitableParentPackage(topMostElementAtPos, diagram);
+ qmt::MPackage *bestParentPackage = d->pxnodeUtilities->createBestMatchingPackagePath(requestedRootPackage, relativeElements);
+ d->diagramSceneController->dropNewModelElement(package, bestParentPackage, pos, diagram);
+ }
+ d->componentViewController->createComponentModel(folderNode, diagram, d->anchorFolder);
+ d->componentViewController->updateIncludeDependencies(package);
+ d->diagramSceneController->getModelController()->getUndoController()->endMergeSequence();
+ }
+ break;
+ }
+ }
+
+ if (newObject) {
+ d->diagramSceneController->getModelController()->getUndoController()->beginMergeSequence(tr("Drop Node"));
+ qmt::MObject *parentForDiagram = 0;
+ QStringList relativeElements = qmt::NameController::buildElementsPath(
+ d->pxnodeUtilities->calcRelativePath(node, d->anchorFolder),
+ dynamic_cast<qmt::MPackage *>(newObject) != 0);
+ if (qmt::MObject *existingObject = d->pxnodeUtilities->findSameObject(relativeElements, newObject)) {
+ delete newObject;
+ newObject = 0;
+ d->diagramSceneController->addExistingModelElement(existingObject->getUid(), pos, diagram);
+ parentForDiagram = existingObject;
+ } else {
+ qmt::MPackage *requestedRootPackage = d->diagramSceneController->findSuitableParentPackage(topMostElementAtPos, diagram);
+ qmt::MPackage *bestParentPackage = d->pxnodeUtilities->createBestMatchingPackagePath(requestedRootPackage, relativeElements);
+ d->diagramSceneController->dropNewModelElement(newObject, bestParentPackage, pos, diagram);
+ parentForDiagram = newObject;
+ }
+
+ // if requested and not existing then create new diagram in package
+ if (newDiagramInObject) {
+ auto package = dynamic_cast<qmt::MPackage *>(parentForDiagram);
+ QTC_ASSERT(package, return);
+ if (d->diagramSceneController->findDiagramBySearchId(package, newDiagramInObject->getName()))
+ delete newDiagramInObject;
+ else
+ d->diagramSceneController->getModelController()->addObject(package, newDiagramInObject);
+ }
+ d->diagramSceneController->getModelController()->getUndoController()->endMergeSequence();
+ }
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/pxnodecontroller.h b/src/plugins/modeleditor/pxnodecontroller.h
new file mode 100644
index 00000000000..eb94b9313b9
--- /dev/null
+++ b/src/plugins/modeleditor/pxnodecontroller.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef PXNODECONTROLLER_H
+#define PXNODECONTROLLER_H
+
+#include <QObject>
+
+namespace ProjectExplorer { class Node; }
+
+namespace qmt {
+class MDiagram;
+class DElement;
+class DiagramSceneController;
+}
+
+namespace ModelEditor {
+namespace Internal {
+
+class PxNodeController :
+ public QObject
+{
+ Q_OBJECT
+ class PxNodeControllerPrivate;
+ class MenuAction;
+
+public:
+ explicit PxNodeController(QObject *parent = 0);
+ ~PxNodeController();
+
+ void setDiagramSceneController(qmt::DiagramSceneController *diagramSceneController);
+ void setAnchorFolder(const QString &anchorFolder);
+
+ void addExplorerNode(const ProjectExplorer::Node *node, qmt::DElement *topMostElementAtPos,
+ const QPointF &pos, qmt::MDiagram *diagram);
+ bool hasDiagramForExplorerNode(const ProjectExplorer::Node *node);
+ qmt::MDiagram *findDiagramForExplorerNode(const ProjectExplorer::Node *node);
+
+private slots:
+ void onMenuActionTriggered(MenuAction *action, const ProjectExplorer::Node *node,
+ qmt::DElement *topMostElementAtPos, const QPointF &pos,
+ qmt::MDiagram *diagram);
+
+private:
+ PxNodeControllerPrivate *d;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // PXNODECONTROLLER_H
diff --git a/src/plugins/modeleditor/pxnodeutilities.cpp b/src/plugins/modeleditor/pxnodeutilities.cpp
new file mode 100644
index 00000000000..5bf72aa8a5b
--- /dev/null
+++ b/src/plugins/modeleditor/pxnodeutilities.cpp
@@ -0,0 +1,246 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "pxnodeutilities.h"
+
+#include "qmt/controller/namecontroller.h"
+#include "qmt/model/mpackage.h"
+#include "qmt/tasks/diagramscenecontroller.h"
+#include "qmt/model_controller/modelcontroller.h"
+
+#include <projectexplorer/projectnodes.h>
+#include <utils/qtcassert.h>
+
+#include <QFileInfo>
+#include <QQueue>
+#include <QPair>
+
+#include <typeinfo>
+
+namespace ModelEditor {
+namespace Internal {
+
+class PxNodeUtilities::PxNodeUtilitiesPrivate {
+public:
+ qmt::DiagramSceneController *diagramSceneController = 0;
+};
+
+PxNodeUtilities::PxNodeUtilities(QObject *parent)
+ : QObject(parent),
+ d(new PxNodeUtilitiesPrivate)
+{
+}
+
+PxNodeUtilities::~PxNodeUtilities()
+{
+ delete d;
+}
+
+void PxNodeUtilities::setDiagramSceneController(qmt::DiagramSceneController *diagramSceneController)
+{
+ d->diagramSceneController = diagramSceneController;
+}
+
+QString PxNodeUtilities::calcRelativePath(const ProjectExplorer::Node *node,
+ const QString &anchorFolder)
+{
+ QString nodePath;
+
+ switch (node->nodeType()) {
+ case ProjectExplorer::FileNodeType:
+ {
+ QFileInfo fileInfo(node->path().toString());
+ nodePath = fileInfo.path();
+ break;
+ }
+ case ProjectExplorer::FolderNodeType:
+ case ProjectExplorer::VirtualFolderNodeType:
+ case ProjectExplorer::ProjectNodeType:
+ nodePath = node->path().toString();
+ break;
+ case ProjectExplorer::SessionNodeType:
+ QTC_ASSERT(false, return QString());
+ break;
+ }
+
+ return qmt::NameController::calcRelativePath(nodePath, anchorFolder);
+}
+
+qmt::MPackage *PxNodeUtilities::createBestMatchingPackagePath(
+ qmt::MPackage *suggestedParentPackage, const QStringList &relativeElements)
+{
+ QSet<qmt::MPackage *> suggestedParents;
+ qmt::MPackage *suggestedParent = suggestedParentPackage;
+ while (suggestedParent) {
+ suggestedParents.insert(suggestedParent);
+ suggestedParent = dynamic_cast<qmt::MPackage *>(suggestedParent->getOwner());
+ }
+
+ QQueue<QPair<qmt::MPackage *, int> > roots;
+ roots.append(qMakePair(d->diagramSceneController->getModelController()->getRootPackage(), 0));
+
+ int maxChainLength = -1;
+ int minChainDepth = -1;
+ qmt::MPackage *bestParentPackage = 0;
+
+ while (!roots.isEmpty()) {
+ qmt::MPackage *package = roots.first().first;
+ int depth = roots.first().second;
+ roots.takeFirst();
+
+ // append all sub-packages of the same level as next root packages
+ foreach (const qmt::Handle<qmt::MObject> &handle, package->getChildren()) {
+ if (handle.hasTarget()) {
+ if (auto childPackage = dynamic_cast<qmt::MPackage *>(handle.getTarget())) {
+ // only accept root packages in the same path as the suggested parent package
+ if (suggestedParents.contains(childPackage)) {
+ roots.append(qMakePair(childPackage, depth + 1));
+ break;
+ }
+ }
+ }
+ }
+
+ // goto into sub-packages to find chain of names
+ int relativeIndex = 0;
+ bool found = true;
+ while (found && relativeIndex < relativeElements.size()) {
+ QString relativeSearchId = qmt::NameController::calcElementNameSearchId(
+ relativeElements.at(relativeIndex));
+ found = false;
+ foreach (const qmt::Handle<qmt::MObject> &handle, package->getChildren()) {
+ if (handle.hasTarget()) {
+ if (auto childPackage = dynamic_cast<qmt::MPackage *>(handle.getTarget())) {
+ if (qmt::NameController::calcElementNameSearchId(childPackage->getName()) == relativeSearchId) {
+ package = childPackage;
+ ++relativeIndex;
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (found)
+ return package; // complete chain found, innermost package is already the result
+
+ QTC_CHECK(!(relativeIndex == maxChainLength && minChainDepth < 0));
+ if (relativeIndex >= 1
+ && (relativeIndex > maxChainLength
+ || (relativeIndex == maxChainLength && depth < minChainDepth))) {
+ maxChainLength = relativeIndex;
+ minChainDepth = depth;
+ bestParentPackage = package;
+ }
+ }
+
+ QTC_CHECK(maxChainLength < relativeElements.size());
+ if (!bestParentPackage) {
+ QTC_CHECK(maxChainLength == -1);
+ QTC_CHECK(minChainDepth == -1);
+ maxChainLength = 0;
+ bestParentPackage = suggestedParentPackage;
+ } else {
+ QTC_CHECK(maxChainLength >= 1);
+ }
+
+ int i = maxChainLength;
+ while (i < relativeElements.size()) {
+ auto newPackage = new qmt::MPackage();
+ newPackage->setFlags(qmt::MElement::REVERSE_ENGINEERED);
+ newPackage->setName(relativeElements.at(i));
+ d->diagramSceneController->getModelController()->addObject(bestParentPackage, newPackage);
+ bestParentPackage = newPackage;
+ ++i;
+ }
+ return bestParentPackage;
+}
+
+qmt::MObject *PxNodeUtilities::findSameObject(const QStringList &relativeElements,
+ const qmt::MObject *object)
+{
+ QQueue<qmt::MPackage *> roots;
+ roots.append(d->diagramSceneController->getModelController()->getRootPackage());
+
+ while (!roots.isEmpty()) {
+ qmt::MPackage *package = roots.takeFirst();
+
+ // append all sub-packages of the same level as next root packages
+ foreach (const qmt::Handle<qmt::MObject> &handle, package->getChildren()) {
+ if (handle.hasTarget()) {
+ if (auto childPackage = dynamic_cast<qmt::MPackage *>(handle.getTarget()))
+ roots.append(childPackage);
+ }
+ }
+
+ // goto into sub-packages to find complete chain of names
+ int relativeIndex = 0;
+ bool found = true;
+ while (found && relativeIndex < relativeElements.size()) {
+ QString relativeSearchId = qmt::NameController::calcElementNameSearchId(
+ relativeElements.at(relativeIndex));
+ found = false;
+ foreach (const qmt::Handle<qmt::MObject> &handle, package->getChildren()) {
+ if (handle.hasTarget()) {
+ if (auto childPackage = dynamic_cast<qmt::MPackage *>(handle.getTarget())) {
+ if (qmt::NameController::calcElementNameSearchId(childPackage->getName()) == relativeSearchId) {
+ package = childPackage;
+ ++relativeIndex;
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (found) {
+ QTC_CHECK(relativeIndex >= relativeElements.size());
+ // chain was found so check for given object within deepest package
+ QString objectSearchId = qmt::NameController::calcElementNameSearchId(object->getName());
+ foreach (const qmt::Handle<qmt::MObject> &handle, package->getChildren()) {
+ if (handle.hasTarget()) {
+ qmt::MObject *target = handle.getTarget();
+ if (typeid(*target) == typeid(*object)
+ && qmt::NameController::calcElementNameSearchId(target->getName()) == objectSearchId) {
+ return target;
+ }
+ }
+ }
+ }
+ }
+
+ // complete sub-package structure scanned but did not found the desired object
+ return 0;
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/pxnodeutilities.h b/src/plugins/modeleditor/pxnodeutilities.h
new file mode 100644
index 00000000000..7022f727689
--- /dev/null
+++ b/src/plugins/modeleditor/pxnodeutilities.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef PXNODEUTILITIES_H
+#define PXNODEUTILITIES_H
+
+#include <QObject>
+
+namespace ProjectExplorer { class Node; }
+
+namespace qmt {
+class MObject;
+class MPackage;
+class DiagramSceneController;
+}
+
+namespace ModelEditor {
+namespace Internal {
+
+class PxNodeUtilities :
+ public QObject
+{
+ Q_OBJECT
+ class PxNodeUtilitiesPrivate;
+
+public:
+ explicit PxNodeUtilities(QObject *parent = 0);
+ ~PxNodeUtilities();
+
+ void setDiagramSceneController(qmt::DiagramSceneController *diagramSceneController);
+
+ QString calcRelativePath(const ProjectExplorer::Node *node, const QString &anchorFolder);
+ qmt::MPackage *createBestMatchingPackagePath(qmt::MPackage *suggestedParentPackage,
+ const QStringList &relativeElements);
+ qmt::MObject *findSameObject(const QStringList &relativeElements,
+ const qmt::MObject *object);
+
+private:
+ PxNodeUtilitiesPrivate *d;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // PXNODEUTILITIES_H
diff --git a/src/plugins/modeleditor/resources/modeleditor.mimetypes.xml b/src/plugins/modeleditor/resources/modeleditor.mimetypes.xml
new file mode 100644
index 00000000000..20d50c5a78f
--- /dev/null
+++ b/src/plugins/modeleditor/resources/modeleditor.mimetypes.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
+ <mime-type type="text/vnd.qtcreator.model">
+ <sub-class-of type="text/xml"/>
+ <comment>Qt Creator Model File</comment>
+ <glob pattern="*.qmodel"/>
+ </mime-type>
+ <mime-type type="text/vnd.qtcreator.diagram-reference">
+ <sub-class-of type="text/xml"/>
+ <comment>Qt Creator Diagram Reference File</comment>
+ <glob pattern="*.qdiagram"/>
+ </mime-type>
+</mime-info>
+
diff --git a/src/plugins/modeleditor/resources/modeleditor.qrc b/src/plugins/modeleditor/resources/modeleditor.qrc
new file mode 100644
index 00000000000..05844c0647b
--- /dev/null
+++ b/src/plugins/modeleditor/resources/modeleditor.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/modeleditor">
+ <file>modeleditor.mimetypes.xml</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/modeleditor/settingscontroller.cpp b/src/plugins/modeleditor/settingscontroller.cpp
new file mode 100644
index 00000000000..a6cb6b45b7d
--- /dev/null
+++ b/src/plugins/modeleditor/settingscontroller.cpp
@@ -0,0 +1,66 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "settingscontroller.h"
+
+#include "modeleditor_constants.h"
+
+#include <QSettings>
+
+namespace ModelEditor {
+namespace Internal {
+
+SettingsController::SettingsController(QObject *parent)
+ : QObject(parent)
+{
+}
+
+void SettingsController::reset()
+{
+ emit resetSettings();
+}
+
+void SettingsController::save(QSettings *settings)
+{
+ settings->beginGroup(QLatin1String(Constants::SETTINGS_GROUP));
+ emit saveSettings(settings);
+ settings->endGroup();
+ settings->sync();
+}
+
+void SettingsController::load(QSettings *settings)
+{
+ settings->beginGroup(QLatin1String(Constants::SETTINGS_GROUP));
+ emit loadSettings(settings);
+ settings->endGroup();
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/settingscontroller.h b/src/plugins/modeleditor/settingscontroller.h
new file mode 100644
index 00000000000..08d569ffd9e
--- /dev/null
+++ b/src/plugins/modeleditor/settingscontroller.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef SETTINGS_H
+#define SETTINGS_H
+
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace ModelEditor {
+namespace Internal {
+
+class SettingsController :
+ public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit SettingsController(QObject *parent = 0);
+
+signals:
+ void resetSettings();
+ void saveSettings(QSettings *settings);
+ void loadSettings(QSettings *settings);
+
+public:
+ void reset();
+ void save(QSettings *settings);
+ void load(QSettings *settings);
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // SETTINGS_H
diff --git a/src/plugins/modeleditor/uicontroller.cpp b/src/plugins/modeleditor/uicontroller.cpp
new file mode 100644
index 00000000000..4690d1c308a
--- /dev/null
+++ b/src/plugins/modeleditor/uicontroller.cpp
@@ -0,0 +1,116 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "uicontroller.h"
+
+#include "modeleditor_constants.h"
+
+#include <QSettings>
+
+namespace ModelEditor {
+namespace Internal {
+
+class UiController::UiControllerPrivate
+{
+public:
+ QByteArray rightSplitterState;
+ QByteArray rightHorizSplitterState;
+};
+
+UiController::UiController(QObject *parent)
+ : QObject(parent),
+ d(new UiControllerPrivate)
+{
+}
+
+UiController::~UiController()
+{
+ delete d;
+}
+
+bool UiController::hasRightSplitterState() const
+{
+ return d->rightSplitterState.size() > 0;
+}
+
+QByteArray UiController::rightSplitterState() const
+{
+ return d->rightSplitterState;
+}
+
+bool UiController::hasRightHorizSplitterState() const
+{
+ return d->rightHorizSplitterState.size() > 0;
+}
+
+QByteArray UiController::rightHorizSplitterState() const
+{
+ return d->rightHorizSplitterState;
+}
+
+void UiController::onRightSplitterChanged(const QByteArray &state)
+{
+ d->rightSplitterState = state;
+ emit rightSplitterChanged(state);
+}
+
+void UiController::onRightHorizSplitterChanged(const QByteArray &state)
+{
+ d->rightHorizSplitterState = state;
+ emit rightHorizSplitterChanged(state);
+}
+
+void UiController::saveSettings(QSettings *settings)
+{
+ if (hasRightSplitterState()) {
+ settings->setValue(
+ QLatin1String(Constants::SETTINGS_RIGHT_SPLITTER), d->rightSplitterState);
+ }
+ if (hasRightHorizSplitterState()) {
+ settings->setValue(
+ QLatin1String(Constants::SETTINGS_RIGHT_HORIZ_SPLITTER),
+ d->rightHorizSplitterState);
+ }
+}
+
+void UiController::loadSettings(QSettings *settings)
+{
+ if (settings->contains(QLatin1String(Constants::SETTINGS_RIGHT_SPLITTER))) {
+ d->rightSplitterState = settings->value(
+ QLatin1String(Constants::SETTINGS_RIGHT_SPLITTER)).value<QByteArray>();
+ }
+ if (settings->contains(QLatin1String(Constants::SETTINGS_RIGHT_HORIZ_SPLITTER))) {
+ d->rightHorizSplitterState = settings->value(
+ QLatin1String(Constants::SETTINGS_RIGHT_HORIZ_SPLITTER)).value<QByteArray>();
+ }
+}
+
+} // namespace Internal
+} // namespace ModelEditor
diff --git a/src/plugins/modeleditor/uicontroller.h b/src/plugins/modeleditor/uicontroller.h
new file mode 100644
index 00000000000..19412324e9f
--- /dev/null
+++ b/src/plugins/modeleditor/uicontroller.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 Jochen Becher
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef UICONTROLLER_H
+#define UICONTROLLER_H
+
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace ModelEditor {
+namespace Internal {
+
+class UiController :
+ public QObject
+{
+ Q_OBJECT
+ class UiControllerPrivate;
+
+public:
+ explicit UiController(QObject *parent = 0);
+ ~UiController();
+
+signals:
+ void rightSplitterChanged(const QByteArray &state);
+ void rightHorizSplitterChanged(const QByteArray &state);
+
+public:
+ bool hasRightSplitterState() const;
+ QByteArray rightSplitterState() const;
+ bool hasRightHorizSplitterState() const;
+ QByteArray rightHorizSplitterState() const;
+
+public slots:
+ void onRightSplitterChanged(const QByteArray &state);
+ void onRightHorizSplitterChanged(const QByteArray &state);
+ void saveSettings(QSettings *settings);
+ void loadSettings(QSettings *settings);
+
+private:
+ UiControllerPrivate *d;
+};
+
+} // namespace Internal
+} // namespace ModelEditor
+
+#endif // UICONTROLLER_H
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
index b39c61e6b5e..cf1904f263f 100644
--- a/src/plugins/plugins.pro
+++ b/src/plugins/plugins.pro
@@ -49,6 +49,7 @@ SUBDIRS = \
baremetal \
ios \
beautifier \
+ modeleditor \
qmakeandroidsupport \
winrt \
qmlprofiler \
diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs
index b323d9c8271..34d5510893b 100644
--- a/src/plugins/plugins.qbs
+++ b/src/plugins/plugins.qbs
@@ -38,6 +38,7 @@ Project {
"ios/ios.qbs",
"macros/macros.qbs",
"mercurial/mercurial.qbs",
+ "modeleditor/modeleditor.qbs",
"perforce/perforce.qbs",
"projectexplorer/projectexplorer.qbs",
"qbsprojectmanager/qbsprojectmanager.qbs",