summaryrefslogtreecommitdiff
path: root/src/plugins/qmldesigner/components
diff options
context:
space:
mode:
authorAleksei German <aleksei.german@qt.io>2019-11-13 12:09:01 +0100
committerAleksei German <aleksei.german@qt.io>2019-11-25 12:24:00 +0000
commit4bf0105bacb5e948e1539809507e252d564d7e8f (patch)
treeb08e3b9b929edf6f01af0d1a6700cd4f65316f67 /src/plugins/qmldesigner/components
parentd48fa5b8d6c797fb2637ada5fbb0009fd9847355 (diff)
downloadqt-creator-4bf0105bacb5e948e1539809507e252d564d7e8f.tar.gz
QmlDesigner Binding Editor structure rework
Separated Binding Editor into 3 files. Cleaned up includes. Change-Id: I84d06148b09cfc0df7db0f5a3a99e0f92997b586 Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
Diffstat (limited to 'src/plugins/qmldesigner/components')
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp377
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h111
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/bindingeditor.pri4
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.cpp258
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.h99
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp160
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.h104
7 files changed, 631 insertions, 482 deletions
diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp
index e56822b2a3..a6fcffa3fb 100644
--- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp
+++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp
@@ -26,393 +26,19 @@
#include "bindingeditor.h"
#include <qmldesignerplugin.h>
-
-#include "texteditorview.h"
-#include "texteditorwidget.h"
-#include <texteditor/texteditor.h>
-
#include <coreplugin/icore.h>
#include <coreplugin/actionmanager/actionmanager.h>
-#include <qmldesigner/qmldesignerplugin.h>
-#include <qmldesigner/qmldesignerconstants.h>
-#include <qmljseditor/qmljseditor.h>
-#include <qmljseditor/qmljseditorconstants.h>
-#include <qmljstools/qmljstoolsconstants.h>
-#include <qmljseditor/qmljscompletionassist.h>
-#include <qmljseditor/qmljshighlighter.h>
-#include <qmljseditor/qmljshoverhandler.h>
-#include <qmljstools/qmljsindenter.h>
-#include <qmljseditor/qmljsautocompleter.h>
-#include <qmljseditor/qmljseditordocument.h>
-#include <qmljseditor/qmljssemantichighlighter.h>
-#include <texteditor/textdocument.h>
-#include <texteditor/texteditoractionhandler.h>
-#include <texteditor/codeassist/assistinterface.h>
-#include <texteditor/codeassist/completionassistprovider.h>
-#include <texteditor/syntaxhighlighter.h>
-#include <projectexplorer/projectexplorerconstants.h>
-#include <coreplugin/editormanager/editormanager.h>
#include <metainfo.h>
#include <qmlmodelnodeproxy.h>
-#include <variantproperty.h>
-#include <bindingproperty.h>
#include <nodeabstractproperty.h>
#include <nodelistproperty.h>
#include <propertyeditorvalue.h>
-#include <QDialogButtonBox>
-#include <QPushButton>
-#include <QDebug>
-#include <QVBoxLayout>
-#include <QHBoxLayout>
-#include <QComboBox>
-#include <QPlainTextEdit>
-
namespace QmlDesigner {
static BindingEditor *s_lastBindingEditor = nullptr;
-const char BINDINGEDITOR_CONTEXT_ID[] = "BindingEditor.BindingEditorContext";
-
-BindingEditorWidget::BindingEditorWidget()
- : m_context(new BindingEditorContext(this))
-{
- Core::ICore::addContextObject(m_context);
-
- const Core::Context context(BINDINGEDITOR_CONTEXT_ID);
-
- /*
- * We have to register our own active auto completion shortcut, because the original short cut will
- * use the cursor position of the original editor in the editor manager.
- */
-
- m_completionAction = new QAction(tr("Trigger Completion"), this);
- Core::Command *command = Core::ActionManager::registerAction(
- m_completionAction, TextEditor::Constants::COMPLETE_THIS, context);
- command->setDefaultKeySequence(QKeySequence(
- Core::useMacShortcuts
- ? tr("Meta+Space")
- : tr("Ctrl+Space")));
-
- connect(m_completionAction, &QAction::triggered, [this]() {
- invokeAssist(TextEditor::Completion);
- });
-}
-
-BindingEditorWidget::~BindingEditorWidget()
-{
- unregisterAutoCompletion();
-
- Core::ICore::removeContextObject(m_context);
- delete m_context;
-}
-
-void BindingEditorWidget::unregisterAutoCompletion()
-{
- if (m_completionAction) {
- Core::ActionManager::unregisterAction(m_completionAction, TextEditor::Constants::COMPLETE_THIS);
- delete m_completionAction;
- m_completionAction = nullptr;
- }
-}
-
-bool BindingEditorWidget::event(QEvent *event)
-{
- if (event->type() == QEvent::KeyPress) {
- QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
- if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) {
- emit returnKeyClicked();
- return true;
- } else {
- return QmlJSEditor::QmlJSEditorWidget::event(event);
- }
- }
- return QmlJSEditor::QmlJSEditorWidget::event(event);
-}
-
-TextEditor::AssistInterface *BindingEditorWidget::createAssistInterface(
- TextEditor::AssistKind assistKind, TextEditor::AssistReason assistReason) const
-{
- Q_UNUSED(assistKind)
- return new QmlJSEditor::QmlJSCompletionAssistInterface(
- document(), position(), QString(),
- assistReason, qmljsdocument->semanticInfo());
-}
-
-class BindingDocument : public QmlJSEditor::QmlJSEditorDocument
-{
-public:
- BindingDocument()
- : QmlJSEditor::QmlJSEditorDocument(BINDINGEDITOR_CONTEXT_ID)
- , m_semanticHighlighter(new QmlJSEditor::SemanticHighlighter(this)) {}
- ~BindingDocument() { delete m_semanticHighlighter; }
-
-protected:
- void applyFontSettings()
- {
- TextDocument::applyFontSettings();
- m_semanticHighlighter->updateFontSettings(fontSettings());
- if (!isSemanticInfoOutdated())
- m_semanticHighlighter->rerun(semanticInfo());
- }
-
- void triggerPendingUpdates()
- {
- TextDocument::triggerPendingUpdates(); // calls applyFontSettings if necessary
- if (!isSemanticInfoOutdated())
- m_semanticHighlighter->rerun(semanticInfo());
- }
-
-private:
- QmlJSEditor::SemanticHighlighter *m_semanticHighlighter = nullptr;
-};
-
-class BindingEditorFactory : public TextEditor::TextEditorFactory
-{
-public:
- BindingEditorFactory()
- {
- setId(BINDINGEDITOR_CONTEXT_ID);
- setDisplayName(QCoreApplication::translate("OpenWith::Editors", BINDINGEDITOR_CONTEXT_ID));
-
-
- setDocumentCreator([]() { return new BindingDocument; });
- setEditorWidgetCreator([]() { return new BindingEditorWidget; });
- setEditorCreator([]() { return new QmlJSEditor::QmlJSEditor; });
- setAutoCompleterCreator([]() { return new QmlJSEditor::AutoCompleter; });
- setCommentDefinition(Utils::CommentDefinition::CppStyle);
- setParenthesesMatchingEnabled(true);
- setCodeFoldingSupported(true);
-
- addHoverHandler(new QmlJSEditor::QmlJSHoverHandler);
- setCompletionAssistProvider(new QmlJSEditor::QmlJSCompletionAssistProvider);
- }
-
- static void decorateEditor(TextEditor::TextEditorWidget *editor)
- {
- editor->textDocument()->setSyntaxHighlighter(new QmlJSEditor::QmlJSHighlighter);
- editor->textDocument()->setIndenter(new QmlJSEditor::Internal::Indenter(
- editor->textDocument()->document()));
- editor->setAutoCompleter(new QmlJSEditor::AutoCompleter);
- }
-};
-
-BindingEditorDialog::BindingEditorDialog(QWidget *parent)
- : QDialog(parent)
-{
- setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
- setWindowTitle(tr("Binding Editor"));
- setModal(false);
-
- setupJSEditor();
- setupUIComponents();
-
- QObject::connect(m_buttonBox, &QDialogButtonBox::accepted,
- this, &BindingEditorDialog::accepted);
- QObject::connect(m_buttonBox, &QDialogButtonBox::rejected,
- this, &BindingEditorDialog::rejected);
- QObject::connect(m_editorWidget, &BindingEditorWidget::returnKeyClicked,
- this, &BindingEditorDialog::accepted);
-
- QObject::connect(m_comboBoxItem, QOverload<int>::of(&QComboBox::currentIndexChanged),
- this, &BindingEditorDialog::itemIDChanged);
- QObject::connect(m_comboBoxProperty, QOverload<int>::of(&QComboBox::currentIndexChanged),
- this, &BindingEditorDialog::propertyIDChanged);
- QObject::connect(m_editorWidget, &QPlainTextEdit::textChanged,
- this, &BindingEditorDialog::textChanged);
-}
-
-BindingEditorDialog::~BindingEditorDialog()
-{
- delete m_editor; //m_editorWidget is handled by basetexteditor destructor
- delete m_buttonBox;
- delete m_comboBoxItem;
- delete m_comboBoxProperty;
- delete m_comboBoxLayout;
- delete m_verticalLayout;
-}
-
-void BindingEditorDialog::showWidget(int x, int y)
-{
- this->show();
- this->raise();
- move(QPoint(x, y));
- m_editorWidget->setFocus();
-}
-
-QString BindingEditorDialog::editorValue() const
-{
- if (!m_editorWidget)
- return {};
-
- return m_editorWidget->document()->toPlainText();
-}
-
-void BindingEditorDialog::setEditorValue(const QString &text)
-{
- if (m_editorWidget)
- m_editorWidget->document()->setPlainText(text);
-}
-
-void BindingEditorDialog::setAllBindings(QList<BindingEditorDialog::BindingOption> bindings)
-{
- m_lock = true;
-
- m_bindings = bindings;
- setupComboBoxes();
- adjustProperties();
-
- m_lock = false;
-}
-
-void BindingEditorDialog::adjustProperties()
-{
- const QString expression = editorValue();
- QString item;
- QString property;
- QStringList expressionElements = expression.split(".");
-
- if (!expressionElements.isEmpty()) {
- const int itemIndex = m_bindings.indexOf(expressionElements.at(0));
-
- if (itemIndex != -1) {
- item = expressionElements.at(0);
- expressionElements.removeFirst();
-
- if (!expressionElements.isEmpty()) {
- const QString sum = expressionElements.join(".");
-
- if (m_bindings.at(itemIndex).properties.contains(sum))
- property = sum;
- }
- }
- }
-
- if (item.isEmpty()) {
- item = undefinedString;
- if (m_comboBoxItem->findText(item) == -1)
- m_comboBoxItem->addItem(item);
- }
- m_comboBoxItem->setCurrentText(item);
-
- if (property.isEmpty()) {
- property = undefinedString;
- if (m_comboBoxProperty->findText(property) == -1)
- m_comboBoxProperty->addItem(property);
- }
- m_comboBoxProperty->setCurrentText(property);
-}
-
-void BindingEditorDialog::unregisterAutoCompletion()
-{
- if (m_editorWidget)
- m_editorWidget->unregisterAutoCompletion();
-}
-
-void BindingEditorDialog::setupJSEditor()
-{
- static BindingEditorFactory f;
- m_editor = qobject_cast<TextEditor::BaseTextEditor*>(f.createEditor());
- m_editorWidget = qobject_cast<BindingEditorWidget*>(m_editor->editorWidget());
-
- Core::Context context = m_editor->context();
- context.prepend(BINDINGEDITOR_CONTEXT_ID);
- m_editorWidget->m_context->setContext(context);
-
- auto qmlDesignerEditor = QmlDesignerPlugin::instance()->currentDesignDocument()->textEditor();
-
- m_editorWidget->qmljsdocument = qobject_cast<QmlJSEditor::QmlJSEditorWidget *>(
- qmlDesignerEditor->widget())->qmlJsEditorDocument();
-
-
- m_editorWidget->setLineNumbersVisible(false);
- m_editorWidget->setMarksVisible(false);
- m_editorWidget->setCodeFoldingSupported(false);
- m_editorWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
- m_editorWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
- m_editorWidget->setTabChangesFocus(true);
-}
-
-void BindingEditorDialog::setupUIComponents()
-{
- m_verticalLayout = new QVBoxLayout(this);
- m_comboBoxLayout = new QHBoxLayout;
-
- m_comboBoxItem = new QComboBox(this);
- m_comboBoxProperty = new QComboBox(this);
-
- m_editorWidget->setParent(this);
- m_editorWidget->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
- m_editorWidget->show();
-
- m_buttonBox = new QDialogButtonBox(this);
- m_buttonBox->setOrientation(Qt::Horizontal);
- m_buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
- m_buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
-
-
- m_comboBoxLayout->addWidget(m_comboBoxItem);
- m_comboBoxLayout->addWidget(m_comboBoxProperty);
-
- m_verticalLayout->addLayout(m_comboBoxLayout);
- m_verticalLayout->addWidget(m_editorWidget);
- m_verticalLayout->addWidget(m_buttonBox);
-
- this->resize(660, 240);
-}
-
-void BindingEditorDialog::setupComboBoxes()
-{
- m_comboBoxItem->clear();
- m_comboBoxProperty->clear();
-
- for (auto bind : m_bindings)
- m_comboBoxItem->addItem(bind.item);
-}
-
-void BindingEditorDialog::itemIDChanged(int itemID)
-{
- const QString previousProperty = m_comboBoxProperty->currentText();
- m_comboBoxProperty->clear();
-
- if (m_bindings.size() > itemID && itemID != -1) {
- m_comboBoxProperty->addItems(m_bindings.at(itemID).properties);
-
- if (!m_lock)
- if (m_comboBoxProperty->findText(previousProperty) != -1)
- m_comboBoxProperty->setCurrentText(previousProperty);
-
- const int undefinedItem = m_comboBoxItem->findText(undefinedString);
- if ((undefinedItem != -1) && (m_comboBoxItem->itemText(itemID) != undefinedString))
- m_comboBoxItem->removeItem(undefinedItem);
- }
-}
-
-void BindingEditorDialog::propertyIDChanged(int propertyID)
-{
- const int itemID = m_comboBoxItem->currentIndex();
-
- if (!m_lock)
- if (!m_comboBoxProperty->currentText().isEmpty() && (m_comboBoxProperty->currentText() != undefinedString))
- setEditorValue(m_comboBoxItem->itemText(itemID) + "." + m_comboBoxProperty->itemText(propertyID));
-
- const int undefinedProperty = m_comboBoxProperty->findText(undefinedString);
- if ((undefinedProperty != -1) && (m_comboBoxProperty->itemText(propertyID) != undefinedString))
- m_comboBoxProperty->removeItem(undefinedProperty);
-}
-
-void BindingEditorDialog::textChanged()
-{
- if (m_lock)
- return;
-
- m_lock = true;
- adjustProperties();
- m_lock = false;
-}
-
-
BindingEditor::BindingEditor(QObject *)
{
}
@@ -556,5 +182,4 @@ QVariant BindingEditor::stateModelNode() const
return m_stateModelNode;
}
-
-}
+} // QmlDesigner namespace
diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h
index a1deb74108..5da06d2ecf 100644
--- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h
+++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h
@@ -26,117 +26,16 @@
#ifndef BINDINGEDITOR_H
#define BINDINGEDITOR_H
-#include "texteditorview.h"
-#include <texteditor/texteditor.h>
-#include <QtQml>
+#include <bindingeditor/bindingeditordialog.h>
+#include <qmldesignercorelib_global.h>
+#include <modelnode.h>
-#include <QWidget>
-#include <QDialog>
+#include <QtQml>
+#include <QObject>
#include <QPointer>
-#include <qmljseditor/qmljseditor.h>
-
-#include <memory>
-
-QT_BEGIN_NAMESPACE
-class QTextEdit;
-class QDialogButtonBox;
-class QVBoxLayout;
-class QHBoxLayout;
-class QComboBox;
-QT_END_NAMESPACE
-
namespace QmlDesigner {
-class BindingEditorContext : public Core::IContext
-{
- Q_OBJECT
-
-public:
- BindingEditorContext(QWidget *parent) : Core::IContext(parent)
- {
- setWidget(parent);
- }
-};
-
-class BindingEditorWidget : public QmlJSEditor::QmlJSEditorWidget
-{
- Q_OBJECT
-
-public:
- BindingEditorWidget();
- ~BindingEditorWidget() override;
-
- void unregisterAutoCompletion();
-
- bool event(QEvent *event) override;
-
- TextEditor::AssistInterface *createAssistInterface(TextEditor::AssistKind assistKind,
- TextEditor::AssistReason assistReason) const override;
-
-signals:
- void returnKeyClicked();
-
-public:
- QmlJSEditor::QmlJSEditorDocument *qmljsdocument = nullptr;
- BindingEditorContext *m_context = nullptr;
- QAction *m_completionAction = nullptr;
-};
-
-class BindingEditorDialog : public QDialog
-{
- Q_OBJECT
-
-public:
- struct BindingOption
- {
- BindingOption() {}
- BindingOption(const QString &value) { item = value; }
-
- bool operator==(const QString &value) const { return value == item; }
- bool operator==(const BindingOption &value) const { return value.item == item; }
-
- QString item;
- QStringList properties;
- };
-
-public:
- BindingEditorDialog(QWidget *parent = nullptr);
- ~BindingEditorDialog() override;
-
- void showWidget(int x, int y);
-
- QString editorValue() const;
- void setEditorValue(const QString &text);
-
- void setAllBindings(QList<BindingEditorDialog::BindingOption> bindings);
- void adjustProperties();
-
- void unregisterAutoCompletion();
-
-private:
- void setupJSEditor();
- void setupUIComponents();
- void setupComboBoxes();
-
-public slots:
- void itemIDChanged(int);
- void propertyIDChanged(int);
- void textChanged();
-
-private:
- TextEditor::BaseTextEditor *m_editor = nullptr;
- BindingEditorWidget *m_editorWidget = nullptr;
- QVBoxLayout *m_verticalLayout = nullptr;
- QDialogButtonBox *m_buttonBox = nullptr;
- QHBoxLayout *m_comboBoxLayout = nullptr;
- QComboBox *m_comboBoxItem = nullptr;
- QComboBox *m_comboBoxProperty = nullptr;
- QList<BindingEditorDialog::BindingOption> m_bindings;
- bool m_lock = false;
- const QString undefinedString = {"[Undefined]"};
-};
-
class BindingEditor : public QObject
{
Q_OBJECT
diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.pri b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.pri
index 518905eb2a..88b2897c7b 100644
--- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.pri
+++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.pri
@@ -1,3 +1,7 @@
HEADERS += $$PWD/bindingeditor.h
+HEADERS += $$PWD/bindingeditordialog.h
+HEADERS += $$PWD/bindingeditorwidget.h
SOURCES += $$PWD/bindingeditor.cpp
+SOURCES += $$PWD/bindingeditordialog.cpp
+SOURCES += $$PWD/bindingeditorwidget.cpp
diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.cpp
new file mode 100644
index 0000000000..08cb5d8bd3
--- /dev/null
+++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.cpp
@@ -0,0 +1,258 @@
+/****************************************************************************
+**
+** 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 "bindingeditordialog.h"
+
+#include <texteditor/texteditor.h>
+
+#include <qmldesigner/qmldesignerplugin.h>
+#include <qmljseditor/qmljseditor.h>
+#include <qmljseditor/qmljseditordocument.h>
+#include <texteditor/textdocument.h>
+
+#include <QDialogButtonBox>
+#include <QPushButton>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QComboBox>
+#include <QPlainTextEdit>
+
+namespace QmlDesigner {
+
+BindingEditorDialog::BindingEditorDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ setWindowTitle(tr("Binding Editor"));
+ setModal(false);
+
+ setupJSEditor();
+ setupUIComponents();
+
+ QObject::connect(m_buttonBox, &QDialogButtonBox::accepted,
+ this, &BindingEditorDialog::accepted);
+ QObject::connect(m_buttonBox, &QDialogButtonBox::rejected,
+ this, &BindingEditorDialog::rejected);
+ QObject::connect(m_editorWidget, &BindingEditorWidget::returnKeyClicked,
+ this, &BindingEditorDialog::accepted);
+
+ QObject::connect(m_comboBoxItem, QOverload<int>::of(&QComboBox::currentIndexChanged),
+ this, &BindingEditorDialog::itemIDChanged);
+ QObject::connect(m_comboBoxProperty, QOverload<int>::of(&QComboBox::currentIndexChanged),
+ this, &BindingEditorDialog::propertyIDChanged);
+ QObject::connect(m_editorWidget, &QPlainTextEdit::textChanged,
+ this, &BindingEditorDialog::textChanged);
+}
+
+BindingEditorDialog::~BindingEditorDialog()
+{
+ delete m_editor; //m_editorWidget is handled by basetexteditor destructor
+ delete m_buttonBox;
+ delete m_comboBoxItem;
+ delete m_comboBoxProperty;
+ delete m_comboBoxLayout;
+ delete m_verticalLayout;
+}
+
+void BindingEditorDialog::showWidget(int x, int y)
+{
+ this->show();
+ this->raise();
+ move(QPoint(x, y));
+ m_editorWidget->setFocus();
+}
+
+QString BindingEditorDialog::editorValue() const
+{
+ if (!m_editorWidget)
+ return {};
+
+ return m_editorWidget->document()->toPlainText();
+}
+
+void BindingEditorDialog::setEditorValue(const QString &text)
+{
+ if (m_editorWidget)
+ m_editorWidget->document()->setPlainText(text);
+}
+
+void BindingEditorDialog::setAllBindings(QList<BindingEditorDialog::BindingOption> bindings)
+{
+ m_lock = true;
+
+ m_bindings = bindings;
+ setupComboBoxes();
+ adjustProperties();
+
+ m_lock = false;
+}
+
+void BindingEditorDialog::adjustProperties()
+{
+ const QString expression = editorValue();
+ QString item;
+ QString property;
+ QStringList expressionElements = expression.split(".");
+
+ if (!expressionElements.isEmpty()) {
+ const int itemIndex = m_bindings.indexOf(expressionElements.at(0));
+
+ if (itemIndex != -1) {
+ item = expressionElements.at(0);
+ expressionElements.removeFirst();
+
+ if (!expressionElements.isEmpty()) {
+ const QString sum = expressionElements.join(".");
+
+ if (m_bindings.at(itemIndex).properties.contains(sum))
+ property = sum;
+ }
+ }
+ }
+
+ if (item.isEmpty()) {
+ item = undefinedString;
+ if (m_comboBoxItem->findText(item) == -1)
+ m_comboBoxItem->addItem(item);
+ }
+ m_comboBoxItem->setCurrentText(item);
+
+ if (property.isEmpty()) {
+ property = undefinedString;
+ if (m_comboBoxProperty->findText(property) == -1)
+ m_comboBoxProperty->addItem(property);
+ }
+ m_comboBoxProperty->setCurrentText(property);
+}
+
+void BindingEditorDialog::unregisterAutoCompletion()
+{
+ if (m_editorWidget)
+ m_editorWidget->unregisterAutoCompletion();
+}
+
+void BindingEditorDialog::setupJSEditor()
+{
+ static BindingEditorFactory f;
+ m_editor = qobject_cast<TextEditor::BaseTextEditor*>(f.createEditor());
+ m_editorWidget = qobject_cast<BindingEditorWidget*>(m_editor->editorWidget());
+
+ Core::Context context = m_editor->context();
+ context.prepend(BINDINGEDITOR_CONTEXT_ID);
+ m_editorWidget->m_context->setContext(context);
+
+ auto qmlDesignerEditor = QmlDesignerPlugin::instance()->currentDesignDocument()->textEditor();
+
+ m_editorWidget->qmljsdocument = qobject_cast<QmlJSEditor::QmlJSEditorWidget *>(
+ qmlDesignerEditor->widget())->qmlJsEditorDocument();
+
+
+ m_editorWidget->setLineNumbersVisible(false);
+ m_editorWidget->setMarksVisible(false);
+ m_editorWidget->setCodeFoldingSupported(false);
+ m_editorWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ m_editorWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ m_editorWidget->setTabChangesFocus(true);
+}
+
+void BindingEditorDialog::setupUIComponents()
+{
+ m_verticalLayout = new QVBoxLayout(this);
+ m_comboBoxLayout = new QHBoxLayout;
+
+ m_comboBoxItem = new QComboBox(this);
+ m_comboBoxProperty = new QComboBox(this);
+
+ m_editorWidget->setParent(this);
+ m_editorWidget->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
+ m_editorWidget->show();
+
+ m_buttonBox = new QDialogButtonBox(this);
+ m_buttonBox->setOrientation(Qt::Horizontal);
+ m_buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ m_buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+
+
+ m_comboBoxLayout->addWidget(m_comboBoxItem);
+ m_comboBoxLayout->addWidget(m_comboBoxProperty);
+
+ m_verticalLayout->addLayout(m_comboBoxLayout);
+ m_verticalLayout->addWidget(m_editorWidget);
+ m_verticalLayout->addWidget(m_buttonBox);
+
+ this->resize(660, 240);
+}
+
+void BindingEditorDialog::setupComboBoxes()
+{
+ m_comboBoxItem->clear();
+ m_comboBoxProperty->clear();
+
+ for (auto bind : m_bindings)
+ m_comboBoxItem->addItem(bind.item);
+}
+
+void BindingEditorDialog::itemIDChanged(int itemID)
+{
+ const QString previousProperty = m_comboBoxProperty->currentText();
+ m_comboBoxProperty->clear();
+
+ if (m_bindings.size() > itemID && itemID != -1) {
+ m_comboBoxProperty->addItems(m_bindings.at(itemID).properties);
+
+ if (!m_lock)
+ if (m_comboBoxProperty->findText(previousProperty) != -1)
+ m_comboBoxProperty->setCurrentText(previousProperty);
+
+ const int undefinedItem = m_comboBoxItem->findText(undefinedString);
+ if ((undefinedItem != -1) && (m_comboBoxItem->itemText(itemID) != undefinedString))
+ m_comboBoxItem->removeItem(undefinedItem);
+ }
+}
+
+void BindingEditorDialog::propertyIDChanged(int propertyID)
+{
+ const int itemID = m_comboBoxItem->currentIndex();
+
+ if (!m_lock)
+ if (!m_comboBoxProperty->currentText().isEmpty() && (m_comboBoxProperty->currentText() != undefinedString))
+ setEditorValue(m_comboBoxItem->itemText(itemID) + "." + m_comboBoxProperty->itemText(propertyID));
+
+ const int undefinedProperty = m_comboBoxProperty->findText(undefinedString);
+ if ((undefinedProperty != -1) && (m_comboBoxProperty->itemText(propertyID) != undefinedString))
+ m_comboBoxProperty->removeItem(undefinedProperty);
+}
+
+void BindingEditorDialog::textChanged()
+{
+ if (m_lock)
+ return;
+
+ m_lock = true;
+ adjustProperties();
+ m_lock = false;
+}
+
+} // QmlDesigner namespace
diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.h b/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.h
new file mode 100644
index 0000000000..f1b224a716
--- /dev/null
+++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** 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 BINDINGEDITORDIALOG_H
+#define BINDINGEDITORDIALOG_H
+
+#include <bindingeditor/bindingeditorwidget.h>
+#include <texteditor/texteditor.h>
+
+#include <QDialog>
+
+QT_BEGIN_NAMESPACE
+class QDialogButtonBox;
+class QVBoxLayout;
+class QHBoxLayout;
+class QComboBox;
+QT_END_NAMESPACE
+
+namespace QmlDesigner {
+
+class BindingEditorDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ struct BindingOption
+ {
+ BindingOption() {}
+ BindingOption(const QString &value) { item = value; }
+
+ bool operator==(const QString &value) const { return value == item; }
+ bool operator==(const BindingOption &value) const { return value.item == item; }
+
+ QString item;
+ QStringList properties;
+ };
+
+public:
+ BindingEditorDialog(QWidget *parent = nullptr);
+ ~BindingEditorDialog() override;
+
+ void showWidget(int x, int y);
+
+ QString editorValue() const;
+ void setEditorValue(const QString &text);
+
+ void setAllBindings(QList<BindingEditorDialog::BindingOption> bindings);
+ void adjustProperties();
+
+ void unregisterAutoCompletion();
+
+private:
+ void setupJSEditor();
+ void setupUIComponents();
+ void setupComboBoxes();
+
+public slots:
+ void itemIDChanged(int);
+ void propertyIDChanged(int);
+ void textChanged();
+
+private:
+ TextEditor::BaseTextEditor *m_editor = nullptr;
+ BindingEditorWidget *m_editorWidget = nullptr;
+ QVBoxLayout *m_verticalLayout = nullptr;
+ QDialogButtonBox *m_buttonBox = nullptr;
+ QHBoxLayout *m_comboBoxLayout = nullptr;
+ QComboBox *m_comboBoxItem = nullptr;
+ QComboBox *m_comboBoxProperty = nullptr;
+ QList<BindingEditorDialog::BindingOption> m_bindings;
+ bool m_lock = false;
+ const QString undefinedString = {"[Undefined]"};
+};
+
+}
+
+#endif //BINDINGEDITORDIALOG_H
diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp
new file mode 100644
index 0000000000..6a058cb49a
--- /dev/null
+++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** 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 "bindingeditorwidget.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <qmljseditor/qmljseditor.h>
+#include <qmljseditor/qmljscompletionassist.h>
+#include <qmljseditor/qmljshighlighter.h>
+#include <qmljseditor/qmljshoverhandler.h>
+#include <qmljseditor/qmljsautocompleter.h>
+#include <qmljseditor/qmljseditordocument.h>
+#include <qmljseditor/qmljssemantichighlighter.h>
+#include <qmljstools/qmljsindenter.h>
+
+#include <QAction>
+
+namespace QmlDesigner {
+
+BindingEditorWidget::BindingEditorWidget()
+ : m_context(new BindingEditorContext(this))
+{
+ Core::ICore::addContextObject(m_context);
+
+ const Core::Context context(BINDINGEDITOR_CONTEXT_ID);
+
+ /*
+ * We have to register our own active auto completion shortcut, because the original short cut will
+ * use the cursor position of the original editor in the editor manager.
+ */
+
+ m_completionAction = new QAction(tr("Trigger Completion"), this);
+ Core::Command *command = Core::ActionManager::registerAction(
+ m_completionAction, TextEditor::Constants::COMPLETE_THIS, context);
+ command->setDefaultKeySequence(QKeySequence(
+ Core::useMacShortcuts
+ ? tr("Meta+Space")
+ : tr("Ctrl+Space")));
+
+ connect(m_completionAction, &QAction::triggered, [this]() {
+ invokeAssist(TextEditor::Completion);
+ });
+}
+
+BindingEditorWidget::~BindingEditorWidget()
+{
+ unregisterAutoCompletion();
+
+ Core::ICore::removeContextObject(m_context);
+ delete m_context;
+}
+
+void BindingEditorWidget::unregisterAutoCompletion()
+{
+ if (m_completionAction) {
+ Core::ActionManager::unregisterAction(m_completionAction, TextEditor::Constants::COMPLETE_THIS);
+ delete m_completionAction;
+ m_completionAction = nullptr;
+ }
+}
+
+bool BindingEditorWidget::event(QEvent *event)
+{
+ if (event->type() == QEvent::KeyPress) {
+ QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
+ if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) {
+ emit returnKeyClicked();
+ return true;
+ } else {
+ return QmlJSEditor::QmlJSEditorWidget::event(event);
+ }
+ }
+ return QmlJSEditor::QmlJSEditorWidget::event(event);
+}
+
+TextEditor::AssistInterface *BindingEditorWidget::createAssistInterface(
+ TextEditor::AssistKind assistKind, TextEditor::AssistReason assistReason) const
+{
+ Q_UNUSED(assistKind)
+ return new QmlJSEditor::QmlJSCompletionAssistInterface(
+ document(), position(), QString(),
+ assistReason, qmljsdocument->semanticInfo());
+}
+
+BindingDocument::BindingDocument()
+ : QmlJSEditor::QmlJSEditorDocument(BINDINGEDITOR_CONTEXT_ID)
+ , m_semanticHighlighter(new QmlJSEditor::SemanticHighlighter(this))
+{
+
+}
+
+BindingDocument::~BindingDocument()
+{
+ delete m_semanticHighlighter;
+}
+
+void BindingDocument::applyFontSettings()
+{
+ TextDocument::applyFontSettings();
+ m_semanticHighlighter->updateFontSettings(fontSettings());
+ if (!isSemanticInfoOutdated())
+ m_semanticHighlighter->rerun(semanticInfo());
+}
+
+void BindingDocument::triggerPendingUpdates()
+{
+ TextDocument::triggerPendingUpdates(); // calls applyFontSettings if necessary
+ if (!isSemanticInfoOutdated())
+ m_semanticHighlighter->rerun(semanticInfo());
+}
+
+BindingEditorFactory::BindingEditorFactory()
+{
+ setId(BINDINGEDITOR_CONTEXT_ID);
+ setDisplayName(QCoreApplication::translate("OpenWith::Editors", QmlDesigner::BINDINGEDITOR_CONTEXT_ID));
+
+ setDocumentCreator([]() { return new BindingDocument; });
+ setEditorWidgetCreator([]() { return new BindingEditorWidget; });
+ setEditorCreator([]() { return new QmlJSEditor::QmlJSEditor; });
+ setAutoCompleterCreator([]() { return new QmlJSEditor::AutoCompleter; });
+ setCommentDefinition(Utils::CommentDefinition::CppStyle);
+ setParenthesesMatchingEnabled(true);
+ setCodeFoldingSupported(true);
+
+ addHoverHandler(new QmlJSEditor::QmlJSHoverHandler);
+ setCompletionAssistProvider(new QmlJSEditor::QmlJSCompletionAssistProvider);
+}
+
+void BindingEditorFactory::decorateEditor(TextEditor::TextEditorWidget *editor)
+{
+ editor->textDocument()->setSyntaxHighlighter(new QmlJSEditor::QmlJSHighlighter);
+ editor->textDocument()->setIndenter(new QmlJSEditor::Internal::Indenter(
+ editor->textDocument()->document()));
+ editor->setAutoCompleter(new QmlJSEditor::AutoCompleter);
+}
+
+} // QmlDesigner namespace
diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.h b/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.h
new file mode 100644
index 0000000000..597051d89f
--- /dev/null
+++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** 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 BINDINGEDITORWIDGET_H
+#define BINDINGEDITORWIDGET_H
+
+#include <texteditor/texteditor.h>
+#include <qmljseditor/qmljseditordocument.h>
+#include <qmljseditor/qmljssemantichighlighter.h>
+#include <qmljseditor/qmljseditor.h>
+
+#include <QtQml>
+#include <QWidget>
+#include <QDialog>
+
+namespace QmlDesigner {
+
+const char BINDINGEDITOR_CONTEXT_ID[] = "BindingEditor.BindingEditorContext";
+
+
+class BindingEditorContext : public Core::IContext
+{
+ Q_OBJECT
+
+public:
+ BindingEditorContext(QWidget *parent) : Core::IContext(parent)
+ {
+ setWidget(parent);
+ }
+};
+
+class BindingEditorWidget : public QmlJSEditor::QmlJSEditorWidget
+{
+ Q_OBJECT
+
+public:
+ BindingEditorWidget();
+ ~BindingEditorWidget() override;
+
+ void unregisterAutoCompletion();
+
+ bool event(QEvent *event) override;
+
+ TextEditor::AssistInterface *createAssistInterface(TextEditor::AssistKind assistKind,
+ TextEditor::AssistReason assistReason) const override;
+
+signals:
+ void returnKeyClicked();
+
+public:
+ QmlJSEditor::QmlJSEditorDocument *qmljsdocument = nullptr;
+ BindingEditorContext *m_context = nullptr;
+ QAction *m_completionAction = nullptr;
+};
+
+class BindingDocument : public QmlJSEditor::QmlJSEditorDocument
+{
+public:
+ BindingDocument();
+ ~BindingDocument();
+
+protected:
+ void applyFontSettings();
+
+ void triggerPendingUpdates();
+
+private:
+ QmlJSEditor::SemanticHighlighter *m_semanticHighlighter = nullptr;
+};
+
+
+class BindingEditorFactory : public TextEditor::TextEditorFactory
+{
+public:
+ BindingEditorFactory();
+
+ static void decorateEditor(TextEditor::TextEditorWidget *editor);
+};
+
+}
+
+#endif //BINDINGEDITORWIDGET_H