QmlDesigner Action Editor for Connections View

Task: QDS-1261
Change-Id: I81e6687e31a0f987ba15dc81dd52f240e4ea9689
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Aleksei German
2019-12-05 14:33:42 +01:00
parent 60f27c609a
commit 0adf810587
14 changed files with 327 additions and 17 deletions

View File

@@ -526,6 +526,7 @@ extend_qtc_plugin(QmlDesigner
extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/bindingeditor SOURCES_PREFIX components/bindingeditor
SOURCES bindingeditor.cpp bindingeditor.h SOURCES bindingeditor.cpp bindingeditor.h
actioneditor.cpp actioneditor.h
bindingeditordialog.cpp bindingeditordialog.h bindingeditordialog.cpp bindingeditordialog.h
bindingeditorwidget.cpp bindingeditorwidget.h bindingeditorwidget.cpp bindingeditorwidget.h
) )

View File

@@ -0,0 +1,131 @@
/****************************************************************************
**
** Copyright (C) 2019 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.
**
****************************************************************************/
#include "actioneditor.h"
#include <qmldesignerplugin.h>
#include <coreplugin/icore.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <metainfo.h>
#include <qmlmodelnodeproxy.h>
#include <nodeabstractproperty.h>
#include <nodelistproperty.h>
#include <propertyeditorvalue.h>
namespace QmlDesigner {
static ActionEditor *s_lastActionEditor = nullptr;
ActionEditor::ActionEditor(QObject *)
: m_index(QModelIndex())
{
}
ActionEditor::~ActionEditor()
{
hideWidget();
}
void ActionEditor::registerDeclarativeType()
{
qmlRegisterType<ActionEditor>("HelperWidgets", 2, 0, "ActionEditor");
}
void ActionEditor::showWidget(int x, int y)
{
if (s_lastActionEditor)
s_lastActionEditor->hideWidget();
s_lastActionEditor = this;
m_dialog = new BindingEditorDialog(Core::ICore::dialogParent(),
BindingEditorDialog::DialogType::ActionDialog);
QObject::connect(m_dialog, &BindingEditorDialog::accepted,
this, &ActionEditor::accepted);
QObject::connect(m_dialog, &BindingEditorDialog::rejected,
this, &ActionEditor::rejected);
m_dialog->setAttribute(Qt::WA_DeleteOnClose);
m_dialog->showWidget(x, y);
m_dialog->activateWindow();
}
void ActionEditor::hideWidget()
{
if (s_lastActionEditor == this)
s_lastActionEditor = nullptr;
if (m_dialog)
{
m_dialog->unregisterAutoCompletion(); //we have to do it separately, otherwise we have an autocompletion action override
m_dialog->close();
}
}
QString ActionEditor::bindingValue() const
{
if (!m_dialog)
return {};
return m_dialog->editorValue();
}
void ActionEditor::setBindingValue(const QString &text)
{
if (m_dialog)
m_dialog->setEditorValue(text);
}
bool ActionEditor::hasModelIndex() const
{
return m_index.isValid();
}
void ActionEditor::resetModelIndex()
{
m_index = QModelIndex();
}
QModelIndex ActionEditor::modelIndex() const
{
return m_index;
}
void ActionEditor::setModelIndex(const QModelIndex &index)
{
m_index = index;
}
void ActionEditor::updateWindowName()
{
if (!m_dialog.isNull())
{
m_dialog->setWindowTitle(tr("Action Editor"));
m_dialog->raise();
}
}
} // QmlDesigner namespace

View File

@@ -0,0 +1,82 @@
/****************************************************************************
**
** Copyright (C) 2019 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.
**
****************************************************************************/
#ifndef ACTIONEDITOR_H
#define ACTIONEDITOR_H
#include <bindingeditor/bindingeditordialog.h>
#include <qmldesignercorelib_global.h>
#include <modelnode.h>
#include <QtQml>
#include <QObject>
#include <QPointer>
namespace QmlDesigner {
class ActionEditor : public QObject
{
Q_OBJECT
Q_PROPERTY(QString text READ bindingValue WRITE setBindingValue)
public:
ActionEditor(QObject *parent = nullptr);
~ActionEditor();
static void registerDeclarativeType();
Q_INVOKABLE void showWidget(int x, int y);
Q_INVOKABLE void hideWidget();
QString bindingValue() const;
void setBindingValue(const QString &text);
bool hasModelIndex() const;
void resetModelIndex();
QModelIndex modelIndex() const;
void setModelIndex(const QModelIndex &index);
Q_INVOKABLE void updateWindowName();
signals:
void accepted();
void rejected();
private:
QVariant backendValue() const;
QVariant modelNodeBackend() const;
QVariant stateModelNode() const;
private:
QPointer<BindingEditorDialog> m_dialog;
QModelIndex m_index;
};
}
QML_DECLARE_TYPE(QmlDesigner::ActionEditor)
#endif //ACTIONEDITOR_H

View File

@@ -1,7 +1,9 @@
HEADERS += $$PWD/bindingeditor.h HEADERS += $$PWD/bindingeditor.h
HEADERS += $$PWD/actioneditor.h
HEADERS += $$PWD/bindingeditordialog.h HEADERS += $$PWD/bindingeditordialog.h
HEADERS += $$PWD/bindingeditorwidget.h HEADERS += $$PWD/bindingeditorwidget.h
SOURCES += $$PWD/bindingeditor.cpp SOURCES += $$PWD/bindingeditor.cpp
SOURCES += $$PWD/actioneditor.cpp
SOURCES += $$PWD/bindingeditordialog.cpp SOURCES += $$PWD/bindingeditordialog.cpp
SOURCES += $$PWD/bindingeditorwidget.cpp SOURCES += $$PWD/bindingeditorwidget.cpp

View File

@@ -41,8 +41,9 @@
namespace QmlDesigner { namespace QmlDesigner {
BindingEditorDialog::BindingEditorDialog(QWidget *parent) BindingEditorDialog::BindingEditorDialog(QWidget *parent, DialogType type)
: QDialog(parent) : QDialog(parent)
, m_dialogType(type)
{ {
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setWindowFlag(Qt::Tool, true); setWindowFlag(Qt::Tool, true);
@@ -59,6 +60,7 @@ BindingEditorDialog::BindingEditorDialog(QWidget *parent)
QObject::connect(m_editorWidget, &BindingEditorWidget::returnKeyClicked, QObject::connect(m_editorWidget, &BindingEditorWidget::returnKeyClicked,
this, &BindingEditorDialog::accepted); this, &BindingEditorDialog::accepted);
if (m_dialogType == DialogType::BindingDialog) {
QObject::connect(m_comboBoxItem, QOverload<int>::of(&QComboBox::currentIndexChanged), QObject::connect(m_comboBoxItem, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &BindingEditorDialog::itemIDChanged); this, &BindingEditorDialog::itemIDChanged);
QObject::connect(m_comboBoxProperty, QOverload<int>::of(&QComboBox::currentIndexChanged), QObject::connect(m_comboBoxProperty, QOverload<int>::of(&QComboBox::currentIndexChanged),
@@ -66,6 +68,7 @@ BindingEditorDialog::BindingEditorDialog(QWidget *parent)
QObject::connect(m_editorWidget, &QPlainTextEdit::textChanged, QObject::connect(m_editorWidget, &QPlainTextEdit::textChanged,
this, &BindingEditorDialog::textChanged); this, &BindingEditorDialog::textChanged);
} }
}
BindingEditorDialog::~BindingEditorDialog() BindingEditorDialog::~BindingEditorDialog()
{ {
@@ -186,10 +189,12 @@ void BindingEditorDialog::setupJSEditor()
void BindingEditorDialog::setupUIComponents() void BindingEditorDialog::setupUIComponents()
{ {
m_verticalLayout = new QVBoxLayout(this); m_verticalLayout = new QVBoxLayout(this);
m_comboBoxLayout = new QHBoxLayout;
if (m_dialogType == DialogType::BindingDialog) {
m_comboBoxLayout = new QHBoxLayout;
m_comboBoxItem = new QComboBox(this); m_comboBoxItem = new QComboBox(this);
m_comboBoxProperty = new QComboBox(this); m_comboBoxProperty = new QComboBox(this);
}
m_editorWidget->setParent(this); m_editorWidget->setParent(this);
m_editorWidget->setFrameStyle(QFrame::StyledPanel | QFrame::Raised); m_editorWidget->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
@@ -200,11 +205,11 @@ void BindingEditorDialog::setupUIComponents()
m_buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); m_buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
m_buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); m_buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
if (m_dialogType == DialogType::BindingDialog) {
m_comboBoxLayout->addWidget(m_comboBoxItem); m_comboBoxLayout->addWidget(m_comboBoxItem);
m_comboBoxLayout->addWidget(m_comboBoxProperty); m_comboBoxLayout->addWidget(m_comboBoxProperty);
m_verticalLayout->addLayout(m_comboBoxLayout); m_verticalLayout->addLayout(m_comboBoxLayout);
}
m_verticalLayout->addWidget(m_editorWidget); m_verticalLayout->addWidget(m_editorWidget);
m_verticalLayout->addWidget(m_buttonBox); m_verticalLayout->addWidget(m_buttonBox);

View File

@@ -57,8 +57,14 @@ public:
QStringList properties; QStringList properties;
}; };
enum DialogType {
Unknown = 0,
BindingDialog = 1,
ActionDialog = 2
};
public: public:
BindingEditorDialog(QWidget *parent = nullptr); BindingEditorDialog(QWidget *parent = nullptr, DialogType type = DialogType::BindingDialog);
~BindingEditorDialog() override; ~BindingEditorDialog() override;
void showWidget(int x, int y); void showWidget(int x, int y);
@@ -84,6 +90,7 @@ public slots:
void textChanged(); void textChanged();
private: private:
DialogType m_dialogType = DialogType::BindingDialog;
TextEditor::BaseTextEditor *m_editor = nullptr; TextEditor::BaseTextEditor *m_editor = nullptr;
BindingEditorWidget *m_editorWidget = nullptr; BindingEditorWidget *m_editorWidget = nullptr;
QVBoxLayout *m_verticalLayout = nullptr; QVBoxLayout *m_verticalLayout = nullptr;

View File

@@ -47,6 +47,7 @@ QStringList propertyNameListToStringList(const QmlDesigner::PropertyNameList &pr
foreach (QmlDesigner::PropertyName propertyName, propertyNameList) { foreach (QmlDesigner::PropertyName propertyName, propertyNameList) {
stringList << QString::fromUtf8(propertyName); stringList << QString::fromUtf8(propertyName);
} }
stringList.removeDuplicates();
return stringList; return stringList;
} }
@@ -281,6 +282,12 @@ void ConnectionModel::variantPropertyChanged(const VariantProperty &variantPrope
resetModel(); resetModel();
} }
void ConnectionModel::abstractPropertyChanged(const AbstractProperty &abstractProperty)
{
if (isConnection(abstractProperty.parentModelNode()))
resetModel();
}
void ConnectionModel::deleteConnectionByRow(int currentRow) void ConnectionModel::deleteConnectionByRow(int currentRow)
{ {
signalHandlerPropertyForRow(currentRow).parentModelNode().destroy(); signalHandlerPropertyForRow(currentRow).parentModelNode().destroy();

View File

@@ -29,6 +29,7 @@
namespace QmlDesigner { namespace QmlDesigner {
class AbstractProperty;
class ModelNode; class ModelNode;
class BindingProperty; class BindingProperty;
class SignalHandlerProperty; class SignalHandlerProperty;
@@ -59,6 +60,7 @@ public:
void bindingPropertyChanged(const BindingProperty &bindingProperty); void bindingPropertyChanged(const BindingProperty &bindingProperty);
void variantPropertyChanged(const VariantProperty &variantProperty); void variantPropertyChanged(const VariantProperty &variantProperty);
void abstractPropertyChanged(const AbstractProperty &abstractProperty);
void deleteConnectionByRow(int currentRow); void deleteConnectionByRow(int currentRow);

View File

@@ -34,6 +34,7 @@
#include <bindingproperty.h> #include <bindingproperty.h>
#include <nodeabstractproperty.h> #include <nodeabstractproperty.h>
#include <variantproperty.h> #include <variantproperty.h>
#include <signalhandlerproperty.h>
namespace QmlDesigner { namespace QmlDesigner {
@@ -139,6 +140,13 @@ void ConnectionView::bindingPropertiesChanged(const QList<BindingProperty> &prop
} }
} }
void ConnectionView::signalHandlerPropertiesChanged(const QVector<SignalHandlerProperty> &propertyList,
AbstractView::PropertyChangeFlags /*propertyChange*/)
{
for (const SignalHandlerProperty &signalHandlerProperty : propertyList)
connectionModel()->abstractPropertyChanged(signalHandlerProperty);
}
void ConnectionView::selectedNodesChanged(const QList<ModelNode> & selectedNodeList, void ConnectionView::selectedNodesChanged(const QList<ModelNode> & selectedNodeList,
const QList<ModelNode> & /*lastSelectedNodeList*/) const QList<ModelNode> & /*lastSelectedNodeList*/)
{ {

View File

@@ -65,6 +65,7 @@ public:
void propertiesAboutToBeRemoved(const QList<AbstractProperty>& propertyList) override; void propertiesAboutToBeRemoved(const QList<AbstractProperty>& propertyList) override;
void variantPropertiesChanged(const QList<VariantProperty>& propertyList, PropertyChangeFlags propertyChange) override; void variantPropertiesChanged(const QList<VariantProperty>& propertyList, PropertyChangeFlags propertyChange) override;
void bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags propertyChange) override; void bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags propertyChange) override;
void signalHandlerPropertiesChanged(const QVector<SignalHandlerProperty>& propertyList, PropertyChangeFlags propertyChange) override;
void selectedNodesChanged(const QList<ModelNode> &selectedNodeList, void selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
const QList<ModelNode> &lastSelectedNodeList) override; const QList<ModelNode> &lastSelectedNodeList) override;

View File

@@ -33,6 +33,7 @@
#include "connectionmodel.h" #include "connectionmodel.h"
#include "dynamicpropertiesmodel.h" #include "dynamicpropertiesmodel.h"
#include "theme.h" #include "theme.h"
#include "signalhandlerproperty.h"
#include <designersettings.h> #include <designersettings.h>
#include <qmldesignerplugin.h> #include <qmldesignerplugin.h>
@@ -43,6 +44,9 @@
#include <QToolButton> #include <QToolButton>
#include <QStyleFactory> #include <QStyleFactory>
#include <QMenu>
#include <bindingeditor/actioneditor.h>
namespace QmlDesigner { namespace QmlDesigner {
@@ -52,6 +56,27 @@ ConnectionViewWidget::ConnectionViewWidget(QWidget *parent) :
QFrame(parent), QFrame(parent),
ui(new Ui::ConnectionViewWidget) ui(new Ui::ConnectionViewWidget)
{ {
m_actionEditor = new QmlDesigner::ActionEditor(this);
QObject::connect(m_actionEditor, &QmlDesigner::ActionEditor::accepted,
[&]() {
if (m_actionEditor->hasModelIndex()) {
ConnectionModel *connectionModel = qobject_cast<ConnectionModel *>(ui->connectionView->model());
if (connectionModel->rowCount() > m_actionEditor->modelIndex().row())
{
SignalHandlerProperty signalHandler =
connectionModel->signalHandlerPropertyForRow(m_actionEditor->modelIndex().row());
signalHandler.setSource(m_actionEditor->bindingValue());
}
m_actionEditor->resetModelIndex();
}
m_actionEditor->hideWidget();
});
QObject::connect(m_actionEditor, &QmlDesigner::ActionEditor::rejected,
[&]() {
m_actionEditor->resetModelIndex();
m_actionEditor->hideWidget();
});
setWindowTitle(tr("Connections", "Title of connection view")); setWindowTitle(tr("Connections", "Title of connection view"));
ui->setupUi(this); ui->setupUi(this);
@@ -96,6 +121,7 @@ ConnectionViewWidget::ConnectionViewWidget(QWidget *parent) :
ConnectionViewWidget::~ConnectionViewWidget() ConnectionViewWidget::~ConnectionViewWidget()
{ {
delete m_actionEditor;
delete ui; delete ui;
} }
@@ -116,9 +142,37 @@ void ConnectionViewWidget::setConnectionModel(ConnectionModel *model)
ui->connectionView->horizontalHeader()->setDefaultSectionSize(160); ui->connectionView->horizontalHeader()->setDefaultSectionSize(160);
ui->connectionView->setSelectionMode(QAbstractItemView::SingleSelection); ui->connectionView->setSelectionMode(QAbstractItemView::SingleSelection);
ui->connectionView->setItemDelegate(new ConnectionDelegate); ui->connectionView->setItemDelegate(new ConnectionDelegate);
connect(ui->connectionView->selectionModel(), &QItemSelectionModel::currentRowChanged, connect(ui->connectionView->selectionModel(), &QItemSelectionModel::currentRowChanged,
this, &ConnectionViewWidget::connectionTableViewSelectionChanged); this, &ConnectionViewWidget::connectionTableViewSelectionChanged);
}
void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event)
{
if (currentTab() != ConnectionTab || ui->connectionView == nullptr)
return;
//adjusting qpoint to the qtableview entrances:
QPoint posInTable(ui->connectionView->mapFromGlobal(mapToGlobal(event->pos())));
posInTable = QPoint(posInTable.x(), posInTable.y() - ui->connectionView->horizontalHeader()->height());
//making sure that we have source column in our hands:
QModelIndex index = ui->connectionView->indexAt(posInTable).siblingAtColumn(ConnectionModel::SourceRow);
if (!index.isValid())
return;
QMenu menu(this);
menu.addAction(tr("Open Action Editor"), [&]() {
if (index.isValid()) {
m_actionEditor->showWidget(mapToGlobal(event->pos()).x(), mapToGlobal(event->pos()).y());
m_actionEditor->setBindingValue(index.data().toString());
m_actionEditor->setModelIndex(index);
m_actionEditor->updateWindowName();
}
});
menu.exec(event->globalPos());
} }
void ConnectionViewWidget::setDynamicPropertiesModel(DynamicPropertiesModel *model) void ConnectionViewWidget::setDynamicPropertiesModel(DynamicPropertiesModel *model)

View File

@@ -38,6 +38,8 @@ namespace QmlDesigner {
namespace Ui { class ConnectionViewWidget; } namespace Ui { class ConnectionViewWidget; }
class ActionEditor;
namespace Internal { namespace Internal {
class BindingModel; class BindingModel;
@@ -88,6 +90,9 @@ signals:
void setEnabledAddButton(bool enabled); void setEnabledAddButton(bool enabled);
void setEnabledRemoveButton(bool enabled); void setEnabledRemoveButton(bool enabled);
protected:
void contextMenuEvent(QContextMenuEvent *event) override;
private: private:
void handleTabChanged(int i); void handleTabChanged(int i);
void removeButtonClicked(); void removeButtonClicked();
@@ -95,6 +100,7 @@ private:
private: private:
Ui::ConnectionViewWidget *ui; Ui::ConnectionViewWidget *ui;
QmlDesigner::ActionEditor *m_actionEditor;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -33,6 +33,7 @@
#include "itemfiltermodel.h" #include "itemfiltermodel.h"
#include "simplecolorpalettemodel.h" #include "simplecolorpalettemodel.h"
#include "bindingeditor/bindingeditor.h" #include "bindingeditor/bindingeditor.h"
#include "bindingeditor/actioneditor.h"
#include "qmlanchorbindingproxy.h" #include "qmlanchorbindingproxy.h"
#include "theme.h" #include "theme.h"
#include "aligndistribute.h" #include "aligndistribute.h"
@@ -60,6 +61,7 @@ void Quick2PropertyEditorView::registerQmlTypes()
SimpleColorPaletteModel::registerDeclarativeType(); SimpleColorPaletteModel::registerDeclarativeType();
Internal::QmlAnchorBindingProxy::registerDeclarativeType(); Internal::QmlAnchorBindingProxy::registerDeclarativeType();
BindingEditor::registerDeclarativeType(); BindingEditor::registerDeclarativeType();
ActionEditor::registerDeclarativeType();
AlignDistribute::registerDeclarativeType(); AlignDistribute::registerDeclarativeType();
} }
} }

View File

@@ -634,6 +634,8 @@ Project {
files: [ files: [
"bindingeditor/bindingeditor.cpp", "bindingeditor/bindingeditor.cpp",
"bindingeditor/bindingeditor.h", "bindingeditor/bindingeditor.h",
"bindingeditor/actioneditor.cpp",
"bindingeditor/actioneditor.h",
"bindingeditor/bindingeditordialog.cpp", "bindingeditor/bindingeditordialog.cpp",
"bindingeditor/bindingeditordialog.h", "bindingeditor/bindingeditordialog.h",
"bindingeditor/bindingeditorwidget.cpp", "bindingeditor/bindingeditorwidget.cpp",