Common EditorProxy interface for Editors

* Introduced a EditorProxy base class to have a common Qml interface for editors

Change-Id: I93af944002801cc3e318653c67dcc464bd9f1213
Reviewed-by: Aleksei German <aleksei.german@qt.io>
Reviewed-by: Tapani Mattila <tapani.mattila@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Michael Winkelmann
2021-03-22 21:14:35 +01:00
parent 83a8e32b3a
commit 27c456dd9e
10 changed files with 305 additions and 248 deletions

View File

@@ -31,6 +31,7 @@ add_qtc_plugin(QmlDesigner
shortcutmanager.cpp shortcutmanager.h
designermcumanager.cpp designermcumanager.h
richtexteditordialog.cpp richtexteditordialog.h
editorproxy.cpp editorproxy.h
EXPLICIT_MOC
components/propertyeditor/propertyeditorvalue.h
components/connectioneditor/connectionviewwidget.h

View File

@@ -25,8 +25,8 @@
#include "annotationeditor.h"
#include "annotationeditordialog.h"
#include "annotation.h"
#include "annotationeditordialog.h"
#include "qmlmodelnodeproxy.h"
@@ -35,126 +35,52 @@
#include <coreplugin/icore.h>
#include <QObject>
#include <QToolBar>
#include <QAction>
#include <QMessageBox>
#include <QObject>
#include <QToolBar>
namespace QmlDesigner {
AnnotationEditor::AnnotationEditor(QObject *parent)
: QObject(parent)
{
}
: ModelNodeEditorProxy(parent)
{}
AnnotationEditor::~AnnotationEditor()
AnnotationEditor::~AnnotationEditor() {}
QWidget *AnnotationEditor::createWidget()
{
hideWidget();
const auto &node = m_modelNode;
auto dialog = new AnnotationEditorDialog(Core::ICore::dialogParent(),
node.id(),
node.customId());
dialog->setAnnotation(node.annotation());
QObject::connect(dialog,
&AnnotationEditorDialog::acceptedDialog,
this,
&AnnotationEditor::acceptedClicked);
QObject::connect(dialog,
&AnnotationEditorDialog::rejected,
this,
&AnnotationEditor::cancelClicked);
return dialog;
}
void AnnotationEditor::registerDeclarativeType()
{
qmlRegisterType<AnnotationEditor>("HelperWidgets", 2, 0, "AnnotationEditor");
}
void AnnotationEditor::showWidget()
{
m_dialog = new AnnotationEditorDialog(Core::ICore::dialogParent(),
m_modelNode.id(),
m_modelNode.customId());
m_dialog->setAnnotation(m_modelNode.annotation());
QObject::connect(m_dialog, &AnnotationEditorDialog::acceptedDialog,
this, &AnnotationEditor::acceptedClicked);
QObject::connect(m_dialog, &AnnotationEditorDialog::rejected,
this, &AnnotationEditor::cancelClicked);
m_dialog->setAttribute(Qt::WA_DeleteOnClose);
m_dialog->show();
m_dialog->raise();
}
void AnnotationEditor::showWidget(int x, int y)
{
showWidget();
m_dialog->move(x, y);
}
void AnnotationEditor::hideWidget()
{
if (m_dialog)
m_dialog->close();
m_dialog = nullptr;
}
AnnotationEditor* AnnotationEditor::showWidget(const ModelNode &modelNode)
{
auto editor = new AnnotationEditor;
editor->setModelNode(modelNode);
editor->showWidget();
connect(editor->m_dialog, &QDialog::destroyed,
[editor]() { editor->deleteLater(); } );
return editor;
}
void AnnotationEditor::setModelNode(const ModelNode &modelNode)
{
m_modelNodeBackend = {};
m_modelNode = modelNode;
}
ModelNode AnnotationEditor::modelNode() const
{
return m_modelNode;
}
void AnnotationEditor::setModelNodeBackend(const QVariant &modelNodeBackend)
{
if (!modelNodeBackend.isNull() && modelNodeBackend.isValid()) {
m_modelNodeBackend = modelNodeBackend;
const auto modelNodeBackendObject = modelNodeBackend.value<QObject*>();
const auto backendObjectCasted =
qobject_cast<const QmlDesigner::QmlModelNodeProxy *>(modelNodeBackendObject);
if (backendObjectCasted)
m_modelNode = backendObjectCasted->qmlObjectNode().modelNode();
emit modelNodeBackendChanged();
}
}
QVariant AnnotationEditor::modelNodeBackend() const
{
return m_modelNodeBackend;
}
bool AnnotationEditor::hasCustomId() const
{
if (m_modelNode.isValid())
return m_modelNode.hasCustomId();
return false;
}
bool AnnotationEditor::hasAnnotation() const
{
if (m_modelNode.isValid())
return m_modelNode.hasAnnotation();
return false;
registerType<AnnotationEditor>("AnnotationEditor");
}
void AnnotationEditor::removeFullAnnotation()
{
if (!m_modelNode.isValid())
auto &node = this->m_modelNode;
if (!node.isValid())
return;
QString dialogTitle = tr("Annotation");
if (!m_modelNode.customId().isNull()) {
dialogTitle = m_modelNode.customId();
if (!node.customId().isNull()) {
dialogTitle = node.customId();
}
QPointer<QMessageBox> deleteDialog = new QMessageBox(Core::ICore::dialogParent());
deleteDialog->setWindowTitle(dialogTitle);
@@ -168,8 +94,8 @@ void AnnotationEditor::removeFullAnnotation()
deleteDialog->deleteLater();
if (result == QMessageBox::Yes) {
m_modelNode.removeCustomId();
m_modelNode.removeAnnotation();
node.removeCustomId();
node.removeAnnotation();
}
emit customIdChanged();
@@ -178,23 +104,23 @@ void AnnotationEditor::removeFullAnnotation()
void AnnotationEditor::acceptedClicked()
{
if (m_dialog) {
if (const auto *dialog = qobject_cast<AnnotationEditorDialog *>(widget())) {
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_ANNOTATION_ADDED);
QString customId = m_dialog->customId();
Annotation annotation = m_dialog->annotation();
const QString customId = dialog->customId();
const Annotation annotation = dialog->annotation();
auto &node = this->m_modelNode;
m_modelNode.setCustomId(customId);
node.setCustomId(customId);
if (annotation.comments().isEmpty())
m_modelNode.removeAnnotation();
node.removeAnnotation();
else
m_modelNode.setAnnotation(annotation);
node.setAnnotation(annotation);
}
hideWidget();
emit accepted();
emit customIdChanged();
emit annotationChanged();
}

View File

@@ -25,65 +25,31 @@
#pragma once
#include <QObject>
#include <QtQml>
#include <QPointer>
#include "annotationeditordialog.h"
#include "annotation.h"
#include "modelnode.h"
#include "editorproxy.h"
namespace QmlDesigner {
class AnnotationEditor : public QObject
class AnnotationEditor : public ModelNodeEditorProxy
{
Q_OBJECT
Q_PROPERTY(QVariant modelNodeBackendProperty READ modelNodeBackend WRITE setModelNodeBackend NOTIFY modelNodeBackendChanged)
Q_PROPERTY(bool hasCustomId READ hasCustomId NOTIFY customIdChanged)
Q_PROPERTY(bool hasAnnotation READ hasAnnotation NOTIFY annotationChanged)
public:
explicit AnnotationEditor(QObject *parent = nullptr);
~AnnotationEditor();
static void registerDeclarativeType();
Q_INVOKABLE void showWidget();
Q_INVOKABLE void showWidget(int x, int y);
Q_INVOKABLE void hideWidget();
static AnnotationEditor* showWidget(const ModelNode &modelNode);
void setModelNode(const ModelNode &modelNode);
ModelNode modelNode() const;
void setModelNodeBackend(const QVariant &modelNodeBackend);
QVariant modelNodeBackend() const;
Q_INVOKABLE bool hasCustomId() const;
Q_INVOKABLE bool hasAnnotation() const;
QWidget *createWidget() override;
Q_INVOKABLE void removeFullAnnotation();
static void registerDeclarativeType();
signals:
void accepted();
void canceled();
void modelNodeBackendChanged();
void customIdChanged();
void annotationChanged();
private slots:
void acceptedClicked();
void cancelClicked();
private:
QPointer<AnnotationEditorDialog> m_dialog;
ModelNode m_modelNode;
QVariant m_modelNodeBackend;
};
} //namespace QmlDesigner

View File

@@ -25,78 +25,40 @@
#include "globalannotationeditor.h"
#include "globalannotationeditordialog.h"
#include "annotation.h"
#include "globalannotationeditordialog.h"
#include "qmlmodelnodeproxy.h"
#include <coreplugin/icore.h>
#include <QObject>
#include <QToolBar>
#include <QAction>
#include <QMessageBox>
namespace QmlDesigner {
GlobalAnnotationEditor::GlobalAnnotationEditor(QObject *)
GlobalAnnotationEditor::GlobalAnnotationEditor(QObject *parent)
: ModelNodeEditorProxy(parent)
{}
GlobalAnnotationEditor::~GlobalAnnotationEditor() {}
QWidget *GlobalAnnotationEditor::createWidget()
{
}
GlobalAnnotationEditor::~GlobalAnnotationEditor()
{
hideWidget();
}
void GlobalAnnotationEditor::showWidget()
{
m_dialog = new GlobalAnnotationEditorDialog(Core::ICore::dialogParent(),
modelNode().globalStatus());
m_dialog->setAnnotation(modelNode().globalAnnotation());
QObject::connect(m_dialog, &GlobalAnnotationEditorDialog::acceptedDialog,
this, &GlobalAnnotationEditor::acceptedClicked);
QObject::connect(m_dialog, &GlobalAnnotationEditorDialog::rejected,
this, &GlobalAnnotationEditor::cancelClicked);
m_dialog->setAttribute(Qt::WA_DeleteOnClose);
m_dialog->show();
m_dialog->raise();
}
void GlobalAnnotationEditor::showWidget(int x, int y)
{
showWidget();
m_dialog->move(x, y);
}
void GlobalAnnotationEditor::hideWidget()
{
if (m_dialog)
m_dialog->close();
m_dialog = nullptr;
}
void GlobalAnnotationEditor::setModelNode(const ModelNode &modelNode)
{
m_modelNode = modelNode;
}
ModelNode GlobalAnnotationEditor::modelNode() const
{
return m_modelNode;
}
bool GlobalAnnotationEditor::hasAnnotation() const
{
if (m_modelNode.isValid())
return m_modelNode.hasGlobalAnnotation();
return false;
}
auto* dialog = new GlobalAnnotationEditorDialog(Core::ICore::dialogParent(),
this->m_modelNode.globalStatus());
dialog->setAnnotation(this->m_modelNode.globalAnnotation());
QObject::connect(dialog,
&GlobalAnnotationEditorDialog::acceptedDialog,
this,
&GlobalAnnotationEditor::acceptedClicked);
QObject::connect(dialog,
&GlobalAnnotationEditorDialog::rejected,
this,
&GlobalAnnotationEditor::cancelClicked);
return dialog;
};
void GlobalAnnotationEditor::removeFullAnnotation()
{
if (!m_modelNode.isValid())
auto &node = this->m_modelNode;
if (!node.isValid())
return;
QString dialogTitle = tr("Global Annotation");
@@ -107,10 +69,11 @@ void GlobalAnnotationEditor::removeFullAnnotation()
deleteDialog->setDefaultButton(QMessageBox::Yes);
int result = deleteDialog->exec();
if (deleteDialog) deleteDialog->deleteLater();
if (deleteDialog)
deleteDialog->deleteLater();
if (result == QMessageBox::Yes) {
m_modelNode.removeGlobalAnnotation();
node.removeGlobalAnnotation();
}
emit annotationChanged();
@@ -118,25 +81,21 @@ void GlobalAnnotationEditor::removeFullAnnotation()
void GlobalAnnotationEditor::acceptedClicked()
{
if (m_dialog) {
Annotation annotation = m_dialog->annotation();
if (const auto *dialog = qobject_cast<GlobalAnnotationEditorDialog *>(widget())) {
auto &node = this->m_modelNode;
const Annotation annotation = dialog->annotation();
if (annotation.comments().isEmpty())
m_modelNode.removeGlobalAnnotation();
node.removeGlobalAnnotation();
else
m_modelNode.setGlobalAnnotation(annotation);
node.setGlobalAnnotation(annotation);
GlobalAnnotationStatus status = m_dialog->globalStatus();
const GlobalAnnotationStatus status = dialog->globalStatus();
if (status.status() == GlobalAnnotationStatus::NoStatus) {
if (m_modelNode.hasGlobalStatus()) {
m_modelNode.removeGlobalStatus();
}
}
else {
m_modelNode.setGlobalStatus(status);
}
if (status.status() == GlobalAnnotationStatus::NoStatus)
node.removeGlobalStatus();
else
node.setGlobalStatus(status);
}
hideWidget();
@@ -150,7 +109,6 @@ void GlobalAnnotationEditor::cancelClicked()
hideWidget();
emit canceled();
emit annotationChanged();
}

View File

@@ -26,32 +26,25 @@
#pragma once
#include <QObject>
#include <QtQml>
#include <QPointer>
#include <QtQml>
#include "globalannotationeditordialog.h"
#include "abstractaction.h"
#include "annotation.h"
#include "globalannotationeditordialog.h"
#include "editorproxy.h"
#include "modelnode.h"
namespace QmlDesigner {
class GlobalAnnotationEditor : public QObject
class GlobalAnnotationEditor : public ModelNodeEditorProxy
{
Q_OBJECT
public:
explicit GlobalAnnotationEditor(QObject *parent = nullptr);
~GlobalAnnotationEditor();
Q_INVOKABLE void showWidget();
Q_INVOKABLE void showWidget(int x, int y);
Q_INVOKABLE void hideWidget();
void setModelNode(const ModelNode &modelNode);
ModelNode modelNode() const;
Q_INVOKABLE bool hasAnnotation() const;
QWidget *createWidget() override;
Q_INVOKABLE void removeFullAnnotation();
@@ -59,17 +52,11 @@ signals:
void accepted();
void canceled();
void modelNodeBackendChanged();
void annotationChanged();
private slots:
void acceptedClicked();
void cancelClicked();
private:
QPointer<GlobalAnnotationEditorDialog> m_dialog;
ModelNode m_modelNode;
};
} //namespace QmlDesigner

View File

@@ -1556,7 +1556,7 @@ void editAnnotation(const SelectionContext &selectionContext)
{
ModelNode selectedNode = selectionContext.currentSingleSelectedNode();
AnnotationEditor::showWidget(selectedNode);
ModelNodeEditorProxy::fromModelNode<AnnotationEditor>(selectedNode);
}
QVariant previewImageDataForGenericNode(const ModelNode &modelNode)

View File

@@ -0,0 +1,114 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "editorproxy.h"
#include "qmlmodelnodeproxy.h"
namespace QmlDesigner {
EditorProxy::EditorProxy(QObject *parent)
: QObject(parent)
{}
EditorProxy::~EditorProxy()
{
hideWidget();
}
void EditorProxy::showWidget()
{
if (m_widget = createWidget()) {
m_widget->setAttribute(Qt::WA_DeleteOnClose);
m_widget->show();
m_widget->raise();
}
}
void EditorProxy::showWidget(int x, int y)
{
showWidget();
if (m_widget) {
m_widget->move(x, y);
}
}
void EditorProxy::hideWidget()
{
if (m_widget)
m_widget->close();
m_widget = nullptr;
}
QWidget* EditorProxy::widget() const {
return m_widget;
}
ModelNodeEditorProxy::ModelNodeEditorProxy(QObject *parent) : EditorProxy(parent) {}
ModelNodeEditorProxy::~ModelNodeEditorProxy() {}
ModelNode ModelNodeEditorProxy::modelNode() const
{
return m_modelNode;
}
void ModelNodeEditorProxy::setModelNode(const ModelNode &modelNode)
{
m_modelNodeBackend = {};
m_modelNode = modelNode;
}
void ModelNodeEditorProxy::setModelNodeBackend(const QVariant &modelNodeBackend)
{
if (!modelNodeBackend.isNull() && modelNodeBackend.isValid()) {
const auto modelNodeBackendObject = modelNodeBackend.value<QObject *>();
const auto backendObjectCasted = qobject_cast<const QmlDesigner::QmlModelNodeProxy *>(
modelNodeBackendObject);
if (backendObjectCasted)
m_modelNode = backendObjectCasted->qmlObjectNode().modelNode();
m_modelNodeBackend = modelNodeBackend;
emit modelNodeBackendChanged();
}
}
QVariant ModelNodeEditorProxy::modelNodeBackend() const
{
return m_modelNodeBackend;
}
bool ModelNodeEditorProxy::hasCustomId() const
{
return m_modelNode.isValid() ? m_modelNode.hasCustomId() : false;
}
bool ModelNodeEditorProxy::hasAnnotation() const
{
return m_modelNode.isValid() ? m_modelNode.hasAnnotation() : false;
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,101 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QQmlEngine>
#include <QPointer>
#include "modelnode.h"
namespace QmlDesigner {
class EditorProxy : public QObject
{
Q_OBJECT
public:
EditorProxy(QObject *parent = nullptr);
~EditorProxy();
Q_INVOKABLE virtual void showWidget();
Q_INVOKABLE void showWidget(int x, int y);
Q_INVOKABLE virtual void hideWidget();
QWidget *widget() const;
virtual QWidget *createWidget() = 0;
template<typename T>
static void registerType(const char *className)
{
qmlRegisterType<T>("HelperWidgets", 2, 0, className);
}
protected:
QPointer<QWidget> m_widget;
};
class ModelNodeEditorProxy : public EditorProxy
{
Q_OBJECT
Q_PROPERTY(bool hasCustomId READ hasCustomId NOTIFY customIdChanged)
Q_PROPERTY(bool hasAnnotation READ hasAnnotation NOTIFY annotationChanged)
Q_PROPERTY(QVariant modelNodeBackendProperty READ modelNodeBackend WRITE setModelNodeBackend
NOTIFY modelNodeBackendChanged)
public:
ModelNodeEditorProxy(QObject *parent = nullptr);
~ModelNodeEditorProxy();
ModelNode modelNode() const;
virtual void setModelNode(const ModelNode &modelNode);
void setModelNodeBackend(const QVariant &modelNodeBackend);
QVariant modelNodeBackend() const;
Q_INVOKABLE bool hasCustomId() const;
Q_INVOKABLE bool hasAnnotation() const;
template<typename T>
static T *fromModelNode(const ModelNode &modelNode, QVariant const &modelNodeBackend = {})
{
auto *editor = new T;
editor->setModelNode(modelNode);
if (!modelNodeBackend.isNull())
editor->setModelNodeBackend(modelNodeBackend);
editor->showWidget();
if (editor->m_widget) {
connect(editor->m_widget, &QObject::destroyed, [editor]() { editor->deleteLater(); });
}
return editor;
}
signals:
void customIdChanged();
void annotationChanged();
void modelNodeBackendChanged();
protected:
QVariant m_modelNodeBackend;
ModelNode m_modelNode;
};
} // namespace QmlDesigner

View File

@@ -3,6 +3,7 @@ HEADERS += $$PWD/qmldesignerconstants.h \
$$PWD/qmldesignerplugin.h \
$$PWD/designmodewidget.h \
$$PWD/designersettings.h \
$$PWD/editorproxy.h \
$$PWD/generateresource.h \
$$PWD/settingspage.h \
$$PWD/designmodecontext.h \
@@ -17,6 +18,7 @@ SOURCES += $$PWD/qmldesignerplugin.cpp \
$$PWD/shortcutmanager.cpp \
$$PWD/designmodewidget.cpp \
$$PWD/designersettings.cpp \
$$PWD/editorproxy.cpp \
$$PWD/generateresource.cpp \
$$PWD/settingspage.cpp \
$$PWD/designmodecontext.cpp \

View File

@@ -977,6 +977,8 @@ Project {
"documentmanager.h",
"documentwarningwidget.cpp",
"documentwarningwidget.h",
"editorproxy.h",
"editorproxy.cpp",
"openuiqmlfiledialog.cpp",
"openuiqmlfiledialog.h",
"openuiqmlfiledialog.ui",