ModelEditor: Implement shared clipboard between all open model-editors

Change-Id: Id2eb6f78f8aa1a698a49d35db6cfceab14a38e0b
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
Jochen Becher
2018-01-07 20:31:02 +01:00
parent bcc550a4e2
commit 4d99f47974
10 changed files with 172 additions and 64 deletions

View File

@@ -487,7 +487,7 @@ DContainer DiagramController::copyElements(const DSelection &diagramSelection, c
return copiedElements;
}
void DiagramController::pasteElements(const DContainer &diagramContainer, MDiagram *diagram)
void DiagramController::pasteElements(const DReferences &diagramContainer, MDiagram *diagram)
{
QMT_ASSERT(diagram, return);

View File

@@ -120,7 +120,7 @@ public:
DContainer cutElements(const DSelection &diagramSelection, MDiagram *diagram);
DContainer copyElements(const DSelection &diagramSelection, const MDiagram *diagram);
void pasteElements(const DContainer &diagramContainer, MDiagram *diagram);
void pasteElements(const DReferences &diagramContainer, MDiagram *diagram);
void deleteElements(const DSelection &diagramSelection, MDiagram *diagram);
private:

View File

@@ -35,7 +35,6 @@
#include "qmt/diagram_ui/diagramsmanager.h"
#include "qmt/diagram_ui/sceneinspector.h"
#include "qmt/model_controller/mcontainer.h"
#include "qmt/model_controller/modelcontroller.h"
#include "qmt/model_controller/mselection.h"
#include "qmt/model/mcanvasdiagram.h"
#include "qmt/model/mclass.h"
@@ -70,9 +69,7 @@ DocumentController::DocumentController(QObject *parent) :
m_treeModel(new TreeModel(this)),
m_sortedTreeModel(new SortedTreeModel(this)),
m_diagramsManager(new DiagramsManager(this)),
m_sceneInspector(new SceneInspector(this)),
m_modelClipboard(new MContainer()),
m_diagramClipboard(new DContainer())
m_sceneInspector(new SceneInspector(this))
{
// project controller
connect(m_projectController, &ProjectController::changed, this, &DocumentController::changed);
@@ -135,44 +132,30 @@ DocumentController::~DocumentController()
delete m_projectController;
}
bool DocumentController::isModelClipboardEmpty() const
{
return m_modelClipboard->isEmpty();
}
bool DocumentController::isDiagramClipboardEmpty() const
{
return m_diagramClipboard->isEmpty();
}
bool DocumentController::hasDiagramSelection(const MDiagram *diagram) const
{
return m_diagramsManager->diagramSceneModel(diagram)->hasSelection();
}
void DocumentController::cutFromModel(const MSelection &selection)
MContainer DocumentController::cutFromModel(const MSelection &selection)
{
*m_modelClipboard = m_modelController->cutElements(selection);
emit modelClipboardChanged(isModelClipboardEmpty());
return m_modelController->cutElements(selection);
}
void DocumentController::cutFromDiagram(MDiagram *diagram)
DContainer DocumentController::cutFromDiagram(MDiagram *diagram)
{
*m_diagramClipboard = m_diagramController->cutElements(m_diagramsManager->diagramSceneModel(diagram)->selectedElements(), diagram);
emit diagramClipboardChanged(isDiagramClipboardEmpty());
return m_diagramController->cutElements(m_diagramsManager->diagramSceneModel(diagram)->selectedElements(), diagram);
}
void DocumentController::copyFromModel(const MSelection &selection)
MContainer DocumentController::copyFromModel(const MSelection &selection)
{
*m_modelClipboard = m_modelController->copyElements(selection);
emit modelClipboardChanged(isModelClipboardEmpty());
return m_modelController->copyElements(selection);
}
void DocumentController::copyFromDiagram(const qmt::MDiagram *diagram)
DContainer DocumentController::copyFromDiagram(const qmt::MDiagram *diagram)
{
m_diagramsManager->diagramSceneModel(diagram)->copyToClipboard();
*m_diagramClipboard = m_diagramController->copyElements(m_diagramsManager->diagramSceneModel(diagram)->selectedElements(), diagram);
emit diagramClipboardChanged(isDiagramClipboardEmpty());
return m_diagramController->copyElements(m_diagramsManager->diagramSceneModel(diagram)->selectedElements(), diagram);
}
void DocumentController::copyDiagram(const MDiagram *diagram)
@@ -180,15 +163,15 @@ void DocumentController::copyDiagram(const MDiagram *diagram)
m_diagramsManager->diagramSceneModel(diagram)->copyToClipboard();
}
void DocumentController::pasteIntoModel(MObject *modelObject)
void DocumentController::pasteIntoModel(MObject *modelObject, const MReferences &container, ModelController::PasteOption option)
{
if (modelObject)
m_modelController->pasteElements(modelObject, *m_modelClipboard);
m_modelController->pasteElements(modelObject, container, option);
}
void DocumentController::pasteIntoDiagram(MDiagram *diagram)
void DocumentController::pasteIntoDiagram(MDiagram *diagram, const DReferences &container)
{
m_diagramController->pasteElements(*m_diagramClipboard, diagram);
m_diagramController->pasteElements(container, diagram);
}
void DocumentController::deleteFromModel(const MSelection &selection)

View File

@@ -27,12 +27,12 @@
#include <QObject>
#include "qmt/infrastructure/qmt_global.h"
#include "qmt/model_controller/modelcontroller.h"
namespace qmt {
class ProjectController;
class UndoController;
class ModelController;
class DiagramController;
class DiagramSceneController;
class StyleController;
@@ -49,6 +49,7 @@ class MDiagram;
class MCanvasDiagram;
class MContainer;
class DContainer;
class DReferences;
class MSelection;
class MObject;
@@ -61,8 +62,6 @@ public:
signals:
void changed();
void modelClipboardChanged(bool isEmpty);
void diagramClipboardChanged(bool isEmpty);
public:
ProjectController *projectController() const { return m_projectController; }
@@ -78,17 +77,15 @@ public:
DiagramsManager *diagramsManager() const { return m_diagramsManager; }
SceneInspector *sceneInspector() const { return m_sceneInspector; }
bool isModelClipboardEmpty() const;
bool isDiagramClipboardEmpty() const;
bool hasDiagramSelection(const qmt::MDiagram *diagram) const;
void cutFromModel(const MSelection &selection);
void cutFromDiagram(MDiagram *diagram);
void copyFromModel(const MSelection &selection);
void copyFromDiagram(const MDiagram *diagram);
MContainer cutFromModel(const MSelection &selection);
DContainer cutFromDiagram(MDiagram *diagram);
MContainer copyFromModel(const MSelection &selection);
DContainer copyFromDiagram(const MDiagram *diagram);
void copyDiagram(const MDiagram *diagram);
void pasteIntoModel(MObject *modelObject);
void pasteIntoDiagram(MDiagram *diagram);
void pasteIntoModel(MObject *modelObject, const MReferences &container, ModelController::PasteOption option);
void pasteIntoDiagram(MDiagram *diagram, const DReferences &container);
void deleteFromModel(const MSelection &selection);
void deleteFromDiagram(MDiagram *diagram);
void removeFromDiagram(MDiagram *diagram);
@@ -118,8 +115,6 @@ private:
SortedTreeModel *m_sortedTreeModel = nullptr;
DiagramsManager *m_diagramsManager = nullptr;
SceneInspector *m_sceneInspector = nullptr;
QScopedPointer<MContainer> m_modelClipboard;
QScopedPointer<DContainer> m_diagramClipboard;
};
} // namespace qmt

View File

@@ -604,16 +604,24 @@ void ModelController::setUndoController(UndoController *undoController)
m_undoController = undoController;
}
Uid ModelController::ownerKey(const Uid &key) const
{
MElement *element = findElement(key);
if (!element)
return Uid::invalidUid();
return ownerKey(element);
}
Uid ModelController::ownerKey(const MElement *element) const
{
QMT_ASSERT(element, return Uid());
MObject *owner = element->owner();
if (!owner)
return Uid();
return Uid::invalidUid();
return owner->uid();
}
MElement *ModelController::findElement(const Uid &key)
MElement *ModelController::findElement(const Uid &key) const
{
if (MObject *object = findObject(key))
return object;
@@ -915,18 +923,21 @@ MContainer ModelController::copyElements(const MSelection &modelSelection)
return copiedElements;
}
void ModelController::pasteElements(MObject *owner, const MContainer &modelContainer)
void ModelController::pasteElements(MObject *owner, const MReferences &modelContainer, PasteOption option)
{
// clone all elements and renew their keys
QHash<Uid, Uid> renewedKeys;
QList<MElement *> clonedElements;
foreach (MElement *element, modelContainer.elements()) {
if (option == PasteAlwaysWithNewKeys || option == PasteAlwaysAndKeepKeys || !findElement(element->uid())) {
MCloneDeepVisitor visitor;
element->accept(&visitor);
MElement *clonedElement = visitor.cloned();
if (option == PasteAlwaysWithNewKeys || (option == PasteAlwaysAndKeepKeys && findElement(element->uid())))
renewElementKey(clonedElement, &renewedKeys);
clonedElements.append(clonedElement);
}
}
// fix all keys referencing between pasting elements
foreach (MElement *clonedElement, clonedElements)
updateRelationKeys(clonedElement, renewedKeys);

View File

@@ -61,6 +61,13 @@ class QMT_EXPORT ModelController : public QObject
class MoveRelationCommand;
public:
enum PasteOption {
PasteAlwaysWithNewKeys,
PasteAlwaysAndKeepKeys,
PasteOnlyNewElements
};
explicit ModelController(QObject *parent = nullptr);
~ModelController() override;
@@ -93,8 +100,9 @@ public:
UndoController *undoController() const { return m_undoController; }
void setUndoController(UndoController *undoController);
Uid ownerKey(const Uid &key) const;
Uid ownerKey(const MElement *element) const;
MElement *findElement(const Uid &key);
MElement *findElement(const Uid &key) const;
template<class T>
T *findElement(const Uid &key) { return dynamic_cast<T *>(findElement(key)); }
@@ -124,7 +132,7 @@ public:
MContainer cutElements(const MSelection &modelSelection);
MContainer copyElements(const MSelection &modelSelection);
void pasteElements(MObject *owner, const MContainer &modelContainer);
void pasteElements(MObject *owner, const MReferences &modelContainer, PasteOption option);
void deleteElements(const MSelection &modelSelection);
private:

View File

@@ -42,6 +42,8 @@
#include "qmt/controller/undocontroller.h"
#include "qmt/diagram/dpackage.h"
#include "qmt/diagram_controller/diagramcontroller.h"
#include "qmt/diagram_controller/dcontainer.h"
#include "qmt/diagram_controller/dreferences.h"
#include "qmt/diagram_controller/dselection.h"
#include "qmt/diagram_scene/diagramscenemodel.h"
#include "qmt/diagram_ui/diagram_mime_types.h"
@@ -51,6 +53,8 @@
#include "qmt/model/mcomponent.h"
#include "qmt/model/mcanvasdiagram.h"
#include "qmt/model_controller/modelcontroller.h"
#include "qmt/model_controller/mcontainer.h"
#include "qmt/model_controller/mreferences.h"
#include "qmt/model_controller/mselection.h"
#include "qmt/model_ui/treemodel.h"
#include "qmt/model_ui/treemodelmanager.h"
@@ -390,7 +394,7 @@ void ModelEditor::initDocument()
d->modelTreeViewServant->setTreeModel(documentController->treeModel());
connect(documentController, &qmt::DocumentController::diagramClipboardChanged,
connect(ModelEditorPlugin::modelsManager(), &ModelsManager::diagramClipboardChanged,
this, &ModelEditor::onDiagramClipboardChanged, Qt::QueuedConnection);
connect(documentController->undoController()->undoStack(), &QUndoStack::canUndoChanged,
this, &ModelEditor::onCanUndoChanged, Qt::QueuedConnection);
@@ -459,15 +463,16 @@ void ModelEditor::redo()
void ModelEditor::cut()
{
ExtDocumentController *documentController = d->document->documentController();
ModelsManager *modelsManager = ModelEditorPlugin::modelsManager();
switch (d->selectedArea) {
case SelectedArea::Nothing:
break;
case SelectedArea::Diagram:
documentController->cutFromDiagram(currentDiagram());
setDiagramClipboard(documentController->cutFromDiagram(currentDiagram()));
break;
case SelectedArea::TreeView:
documentController->cutFromModel(d->modelTreeViewServant->selectedObjects());
modelsManager->setModelClipboard(documentController, documentController->cutFromModel(d->modelTreeViewServant->selectedObjects()));
break;
}
}
@@ -475,18 +480,19 @@ void ModelEditor::cut()
void ModelEditor::copy()
{
ExtDocumentController *documentController = d->document->documentController();
ModelsManager *modelsManager = ModelEditorPlugin::modelsManager();
switch (d->selectedArea) {
case SelectedArea::Nothing:
break;
case SelectedArea::Diagram:
if (documentController->hasDiagramSelection(currentDiagram()))
documentController->copyFromDiagram(currentDiagram());
setDiagramClipboard(documentController->copyFromDiagram(currentDiagram()));
else
documentController->copyDiagram(currentDiagram());
break;
case SelectedArea::TreeView:
documentController->copyFromModel(d->modelTreeViewServant->selectedObjects());
modelsManager->setModelClipboard(documentController, documentController->copyFromModel(d->modelTreeViewServant->selectedObjects()));
break;
}
}
@@ -494,15 +500,20 @@ void ModelEditor::copy()
void ModelEditor::paste()
{
ExtDocumentController *documentController = d->document->documentController();
ModelsManager *modelsManager = ModelEditorPlugin::modelsManager();
switch (d->selectedArea) {
case SelectedArea::Nothing:
break;
case SelectedArea::Diagram:
documentController->pasteIntoDiagram(currentDiagram());
// on cut/copy diagram and model elements were copied.
documentController->pasteIntoModel(currentDiagram(), modelsManager->modelClipboard(), qmt::ModelController::PasteOnlyNewElements);
documentController->pasteIntoDiagram(currentDiagram(), modelsManager->diagramClipboard());
break;
case SelectedArea::TreeView:
documentController->pasteIntoModel(d->modelTreeViewServant->selectedObject());
documentController->pasteIntoModel(d->modelTreeViewServant->selectedObject(), modelsManager->modelClipboard(),
documentController == modelsManager->modelClipboardDocumentController()
? qmt::ModelController::PasteAlwaysWithNewKeys : qmt::ModelController::PasteAlwaysAndKeepKeys);
break;
}
}
@@ -656,6 +667,7 @@ void ModelEditor::updateSelectedArea(SelectedArea selectedArea)
d->selectedArea = selectedArea;
qmt::DocumentController *documentController = d->document->documentController();
ModelsManager *modelsManager = ModelEditorPlugin::modelsManager();
bool canCutCopyDelete = false;
bool canRemove = false;
bool canPaste = false;
@@ -680,7 +692,7 @@ void ModelEditor::updateSelectedArea(SelectedArea selectedArea)
bool hasSelection = documentController->diagramsManager()->diagramSceneModel(activeDiagram)->hasSelection();
canCutCopyDelete = hasSelection;
canRemove = hasSelection;
canPaste = !documentController->isDiagramClipboardEmpty();
canPaste = !modelsManager->isDiagramClipboardEmpty();
canSelectAll = !activeDiagram->diagramElements().isEmpty();
canCopyDiagram = !hasSelection;
canExportDiagram = true;
@@ -705,7 +717,7 @@ void ModelEditor::updateSelectedArea(SelectedArea selectedArea)
bool hasSelection = !d->modelTreeViewServant->selectedObjects().isEmpty();
bool hasSingleSelection = d->modelTreeViewServant->selectedObjects().indices().size() == 1;
canCutCopyDelete = hasSelection && !d->modelTreeViewServant->isRootPackageSelected();
canPaste = hasSingleSelection && !documentController->isModelClipboardEmpty();
canPaste = hasSingleSelection && !modelsManager->isModelClipboardEmpty();
canSelectAll = activeDiagram && !activeDiagram->diagramElements().isEmpty();
canExportDiagram = activeDiagram != nullptr;
QModelIndexList indexes = d->modelTreeView->selectedSourceModelIndexes();
@@ -1224,6 +1236,20 @@ void ModelEditor::onContentSet()
expandModelTreeToDepth(0);
}
void ModelEditor::setDiagramClipboard(const qmt::DContainer &dcontainer)
{
ExtDocumentController *documentController = d->document->documentController();
qmt::ModelController *modelController = documentController->modelController();
qmt::MSelection modelSelection;
for (const auto &delement : dcontainer.elements()) {
qmt::Uid melementUid = delement->modelUid();
qmt::Uid mownerUid = modelController->ownerKey(melementUid);
modelSelection.append(melementUid, mownerUid);
}
qmt::MContainer mcontainer = modelController->copyElements(modelSelection);
ModelEditorPlugin::modelsManager()->setDiagramClipboard(documentController, dcontainer, mcontainer);
}
void ModelEditor::addDiagramToSelector(const qmt::MDiagram *diagram)
{
QString diagramLabel = buildDiagramLabel(diagram);

View File

@@ -41,6 +41,7 @@ class MElement;
class MPackage;
class MDiagram;
class DElement;
class DContainer;
class DocumentController;
}
@@ -140,6 +141,8 @@ private:
void onContentSet();
void setDiagramClipboard(const qmt::DContainer &dcontainer);
void addDiagramToSelector(const qmt::MDiagram *diagram);
void updateDiagramSelector();
void onDiagramSelectorSelected(int index);

View File

@@ -34,10 +34,14 @@
#include "pxnodecontroller.h"
#include "qmt/config/configcontroller.h"
#include "qmt/diagram_controller/dcontainer.h"
#include "qmt/diagram_controller/dreferences.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/model_controller/mcontainer.h"
#include "qmt/model_controller/mreferences.h"
#include "qmt/project_controller/projectcontroller.h"
#include "qmt/project/project.h"
#include "qmt/stereotype/stereotypecontroller.h"
@@ -91,6 +95,11 @@ public:
ModelIndexer *modelIndexer = nullptr;
QList<Core::IDocument *> documentsToBeClosed;
ExtDocumentController *modelClipboardDocumentController = nullptr;
qmt::MContainer modelClipboard;
ExtDocumentController *diagramClipboardDocumentController = nullptr;
qmt::DContainer diagramClipboard;
QAction *openDiagramContextMenuItem = nullptr;
ProjectExplorer::Node *contextMenuOwnerNode = nullptr;
};
@@ -142,6 +151,10 @@ ExtDocumentController *ModelsManager::createModel(ModelDocument *modelDocument)
void ModelsManager::releaseModel(ExtDocumentController *documentController)
{
if (documentController == d->modelClipboardDocumentController)
d->modelClipboardDocumentController = nullptr;
if (documentController == d->diagramClipboardDocumentController)
d->diagramClipboardDocumentController = nullptr;
for (int i = 0; i < d->managedModels.size(); ++i) {
ManagedModel *managedModel = &d->managedModels[i];
if (managedModel->m_documentController == documentController) {
@@ -165,6 +178,55 @@ void ModelsManager::openDiagram(const qmt::Uid &modelUid, const qmt::Uid &diagra
}
}
bool ModelsManager::isModelClipboardEmpty() const
{
return d->modelClipboard.isEmpty();
}
ExtDocumentController *ModelsManager::modelClipboardDocumentController() const
{
return d->modelClipboardDocumentController;
}
qmt::MReferences ModelsManager::modelClipboard() const
{
qmt::MReferences clipboard;
clipboard.setElements(d->modelClipboard.elements());
return clipboard;
}
void ModelsManager::setModelClipboard(ExtDocumentController *documentController, const qmt::MContainer &container)
{
d->modelClipboardDocumentController = documentController;
d->modelClipboard = container;
emit modelClipboardChanged(isModelClipboardEmpty());
}
bool ModelsManager::isDiagramClipboardEmpty() const
{
return d->diagramClipboard.isEmpty();
}
ExtDocumentController *ModelsManager::diagramClipboardDocumentController() const
{
return d->diagramClipboardDocumentController;
}
qmt::DReferences ModelsManager::diagramClipboard() const
{
qmt::DReferences clipboard;
clipboard.setElements(d->diagramClipboard.elements());
return clipboard;
}
void ModelsManager::setDiagramClipboard(ExtDocumentController *documentController, const qmt::DContainer &dcontainer, const qmt::MContainer &mcontainer)
{
setModelClipboard(documentController, mcontainer);
d->diagramClipboardDocumentController = documentController;
d->diagramClipboard = dcontainer;
emit diagramClipboardChanged(isDiagramClipboardEmpty());
}
void ModelsManager::onAboutToShowContextMenu(ProjectExplorer::Project *project,
ProjectExplorer::Node *node)
{

View File

@@ -36,6 +36,10 @@ namespace qmt {
class Uid;
class MDiagram;
class DiagramsViewInterface;
class MContainer;
class MReferences;
class DContainer;
class DReferences;
}
namespace ModelEditor {
@@ -56,10 +60,26 @@ public:
explicit ModelsManager(QObject *parent = nullptr);
~ModelsManager();
signals:
void modelClipboardChanged(bool isEmpty);
void diagramClipboardChanged(bool isEmpty);
public:
ExtDocumentController *createModel(ModelDocument *modelDocument);
void releaseModel(ExtDocumentController *documentController);
void openDiagram(const qmt::Uid &modelUid, const qmt::Uid &diagramUid);
bool isModelClipboardEmpty() const;
ExtDocumentController *modelClipboardDocumentController() const;
qmt::MReferences modelClipboard() const;
void setModelClipboard(ExtDocumentController *documentController, const qmt::MContainer &container);
bool isDiagramClipboardEmpty() const;
ExtDocumentController *diagramClipboardDocumentController() const;
qmt::DReferences diagramClipboard() const;
void setDiagramClipboard(ExtDocumentController *documentController, const qmt::DContainer &dcontainer,
const qmt::MContainer &mcontainer);
private:
void onAboutToShowContextMenu(ProjectExplorer::Project *project, ProjectExplorer::Node *node);
void onOpenDiagramFromProjectExplorer();