summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEike Ziller <eike.ziller@qt.io>2020-09-17 10:28:19 +0200
committerEike Ziller <eike.ziller@qt.io>2020-09-17 10:28:19 +0200
commit5ad724c61bc78cad19b265b177635c1e48bcbbaf (patch)
tree53d7e9467d0b62396535224b9d89866ae4509d23 /src
parent0d185a0ad3f3efc2690356c7567d8351827deb88 (diff)
parent364288b79cfb27f4bea9a7a41b785660fb8d0dde (diff)
downloadqt-creator-5ad724c61bc78cad19b265b177635c1e48bcbbaf.tar.gz
Merge remote-tracking branch 'origin/4.13' into master
Conflicts: src/plugins/qmakeprojectmanager/qmakeproject.cpp Change-Id: Ieb1c3e946f11d3c4fa1ee6b5afdf83cc532d8aed
Diffstat (limited to 'src')
-rw-r--r--src/libs/libs.pro10
-rw-r--r--src/libs/qmljs/qmljscheck.cpp5
-rw-r--r--src/libs/qtcreatorcdbext/CMakeLists.txt25
-rw-r--r--src/libs/qtcreatorcdbext/cdb_detect.pri25
-rw-r--r--src/libs/qtcreatorcdbext/qtcreatorcdbext.pro29
-rw-r--r--src/libs/qtcreatorcdbext/qtcreatorcdbext.qbs47
-rw-r--r--src/libs/utils/outputformatter.cpp2
-rw-r--r--src/plugins/autotest/boost/boosttestoutputreader.cpp5
-rw-r--r--src/plugins/autotest/testrunner.cpp16
-rw-r--r--src/plugins/coreplugin/outputwindow.cpp5
-rw-r--r--src/plugins/cppeditor/cppdoxygen_test.cpp4
-rw-r--r--src/plugins/debugger/debuggerengine.cpp10
-rw-r--r--src/plugins/projectexplorer/project.cpp27
-rw-r--r--src/plugins/projectexplorer/project.h9
-rw-r--r--src/plugins/python/pythonrunconfiguration.cpp4
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp35
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeproject.cpp44
-rw-r--r--src/plugins/qmldesigner/CMakeLists.txt3
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.cpp183
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.h93
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/actioneditor.cpp183
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/actioneditor.h18
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/actioneditordialog.cpp656
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/actioneditordialog.h155
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp42
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/bindingeditor.pri6
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.cpp150
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.h48
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/connectionvisitor.cpp112
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/connectionvisitor.h66
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp58
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp4
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h2
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp36
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.h2
-rw-r--r--src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp14
-rw-r--r--src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.h5
-rw-r--r--src/plugins/qmldesigner/documentmanager.cpp7
-rw-r--r--src/plugins/qmldesigner/documentmanager.h2
-rw-r--r--src/plugins/qmldesigner/qmldesignerplugin.qbs6
-rw-r--r--src/plugins/texteditor/textmark.cpp6
-rw-r--r--src/tools/clangbackend/source/tokeninfo.cpp1
42 files changed, 1713 insertions, 447 deletions
diff --git a/src/libs/libs.pro b/src/libs/libs.pro
index 013376911f..9675dca049 100644
--- a/src/libs/libs.pro
+++ b/src/libs/libs.pro
@@ -65,16 +65,8 @@ isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR) {
win32:SUBDIRS += utils/process_ctrlc_stub.pro
-# Windows: Compile Qt Creator CDB extension if Debugging tools can be detected.
win32: isEmpty(QTC_SKIP_CDBEXT) {
- include(qtcreatorcdbext/cdb_detect.pri)
- !isEmpty(CDB_PATH): exists($$CDB_PATH) {
- SUBDIRS += qtcreatorcdbext
- } else {
- message("Compiling Qt Creator without a CDB extension.")
- message("If CDB is installed in a none default path define a CDB_PATH")
- message("environment variable pointing to your CDB installation.")
- }
+ SUBDIRS += qtcreatorcdbext
}
QMAKE_EXTRA_TARGETS += deployqt # dummy
diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp
index 92e1c1e59c..375cb9b452 100644
--- a/src/libs/qmljs/qmljscheck.cpp
+++ b/src/libs/qmljs/qmljscheck.cpp
@@ -1838,7 +1838,10 @@ const Value *Check::checkScopeObjectMember(const UiQualifiedId *id)
const bool isListElementScope = (!m_typeStack.isEmpty() && m_typeStack.last() == "ListElement");
- if (!value && !isListElementScope) {
+ if (isListElementScope)
+ return nullptr;
+
+ if (!value) {
addMessage(ErrInvalidPropertyName, id->identifierToken, propertyName);
return nullptr;
}
diff --git a/src/libs/qtcreatorcdbext/CMakeLists.txt b/src/libs/qtcreatorcdbext/CMakeLists.txt
index 329a228afc..394405f37f 100644
--- a/src/libs/qtcreatorcdbext/CMakeLists.txt
+++ b/src/libs/qtcreatorcdbext/CMakeLists.txt
@@ -2,30 +2,7 @@ if (NOT WIN32 OR NOT MSVC)
return()
endif()
-find_path(WDbgExtsPath wdbgexts.h
- HINTS
- "$ENV{CDB_PATH}"
- "$ENV{ProgramFiles}/Debugging Tools For Windows/sdk"
- "$ENV{ProgramFiles}/Debugging Tools For Windows (x86)/sdk"
- "$ENV{ProgramFiles}/Debugging Tools For Windows (x64)/sdk"
- "$ENV{ProgramFiles}/Debugging Tools For Windows 64-bit/sdk"
- "$ENV{ProgramW6432}/Debugging Tools For Windows (x86)/sdk"
- "$ENV{ProgramW6432}/Debugging Tools For Windows (x64)/sdk"
- "$ENV{ProgramW6432}/Debugging Tools For Windows 64-bit/sdk"
- "$ENV{ProgramFiles}/Windows Kits/8.0/Debuggers"
- "$ENV{ProgramFiles}/Windows Kits/8.1/Debuggers"
- "$ENV{ProgramFiles}/Windows Kits/10/Debuggers"
- "$ENV{ProgramFiles\(x86\)}/Windows Kits/8.0/Debuggers/inc"
- "$ENV{ProgramFiles\(x86\)}/Windows Kits/8.1/Debuggers/inc"
- "$ENV{ProgramFiles\(x86\)}/Windows Kits/10/Debuggers/inc"
-)
-
-if (NOT WDbgExtsPath)
- message(WARNING "wdbgexts.h not found. Removing qtcreatorcdbext from build.")
- return()
-endif()
-
-find_library(DbgEngLib dbgeng HINTS ${WDbgExtsPath})
+find_library(DbgEngLib dbgeng)
set(ArchSuffix 32)
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
diff --git a/src/libs/qtcreatorcdbext/cdb_detect.pri b/src/libs/qtcreatorcdbext/cdb_detect.pri
deleted file mode 100644
index ae09e258d4..0000000000
--- a/src/libs/qtcreatorcdbext/cdb_detect.pri
+++ /dev/null
@@ -1,25 +0,0 @@
-# Detect presence of "Debugging Tools For Windows"
-# in case MS VS compilers are used.
-
-CDB_PATH=""
-msvc {
- CDB_PATH="$$(CDB_PATH)"
- isEmpty(CDB_PATH):CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows/sdk"
- !exists($$CDB_PATH):CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows (x86)/sdk"
- !exists($$CDB_PATH):CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows (x64)/sdk"
- !exists($$CDB_PATH):CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows 64-bit/sdk"
- !exists($$CDB_PATH):CDB_PATH="$$(ProgramW6432)/Debugging Tools For Windows (x86)/sdk"
- !exists($$CDB_PATH):CDB_PATH="$$(ProgramW6432)/Debugging Tools For Windows (x64)/sdk"
- !exists($$CDB_PATH):CDB_PATH="$$(ProgramW6432)/Debugging Tools For Windows 64-bit/sdk"
-# Starting from Windows SDK 8, the headers and libs are under 'ProgramFiles (x86)'.
-# The libraries are under 'ProgramFiles'as well, so, check for existence of 'inc'.
-# 32bit qmake:
- !exists($$CDB_PATH/inc):CDB_PATH="$$(ProgramFiles)/Windows Kits/8.0/Debuggers"
- !exists($$CDB_PATH/inc):CDB_PATH="$$(ProgramFiles)/Windows Kits/8.1/Debuggers"
- !exists($$CDB_PATH/inc):CDB_PATH="$$(ProgramFiles)/Windows Kits/10/Debuggers"
-# 64bit qmake:
- !exists($$CDB_PATH/inc):CDB_PATH="$$(ProgramFiles) (x86)/Windows Kits/8.0/Debuggers"
- !exists($$CDB_PATH/inc):CDB_PATH="$$(ProgramFiles) (x86)/Windows Kits/8.1/Debuggers"
- !exists($$CDB_PATH/inc):CDB_PATH="$$(ProgramFiles) (x86)/Windows Kits/10/Debuggers"
- !exists($$CDB_PATH/inc):CDB_PATH=""
-}
diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbext.pro b/src/libs/qtcreatorcdbext/qtcreatorcdbext.pro
index 774e889b2a..98961887b9 100644
--- a/src/libs/qtcreatorcdbext/qtcreatorcdbext.pro
+++ b/src/libs/qtcreatorcdbext/qtcreatorcdbext.pro
@@ -2,7 +2,6 @@
TEMPLATE = lib
include(../../../qtcreator.pri)
-include(cdb_detect.pri)
isEmpty(QTC_KEEP_CDBEXT_DEFAULT_CONFIG): CONFIG += release
@@ -30,45 +29,21 @@ DEF_FILE=$$PWD/qtcreatorcdbext.def
ENV_TARGET_ARCH=$$(VSCMD_ARG_TGT_ARCH)
isEmpty(ENV_TARGET_ARCH):ENV_TARGET_ARCH = $$(Platform)
-ENV_LIBPATH=$$(LIBPATH)
contains(ENV_TARGET_ARCH, .*64$) {
DIRNAME=$${BASENAME}64
CDB_PLATFORM=amd64
-
- exists($$CDB_PATH/lib/amd64) {
- LIBS+= -L$$CDB_PATH/lib/amd64 -ldbgeng
- } else {
- LIBS+= -L$$CDB_PATH/lib/x64 -ldbgeng
- }
-} else:isEmpty(ENV_TARGET_ARCH):contains(ENV_LIBPATH, ^.*amd64.*$) {
- DIRNAME=$${BASENAME}64
- CDB_PLATFORM=amd64
-
- exists($$CDB_PATH/lib/amd64) {
- LIBS+= -L$$CDB_PATH/lib/amd64 -ldbgeng
- } else {
- LIBS+= -L$$CDB_PATH/lib/x64 -ldbgeng
- }
} else {
DIRNAME=$${BASENAME}32
CDB_PLATFORM=i386
-
- exists($$CDB_PATH/lib/i386}) {
- LIBS+= -L$$CDB_PATH/lib/i386 -ldbgeng
- } else {
- LIBS+= -L$$CDB_PATH/lib/x86 -ldbgeng
- }
}
-LIBS+=-luser32
+LIBS+=-ldbgeng -luser32
DESTDIR=$$IDE_BUILD_TREE/lib/$${DIRNAME}
TARGET = $$BASENAME
-message("Compiling Qt Creator CDB extension $$TARGET $$DESTDIR for $$CDB_PLATFORM using $$CDB_PATH")
-
-INCLUDEPATH += $$CDB_PATH/inc
+message("Compiling Qt Creator CDB extension $$TARGET $$DESTDIR for $$CDB_PLATFORM")
CONFIG -= qt
QT -= gui
diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbext.qbs b/src/libs/qtcreatorcdbext/qtcreatorcdbext.qbs
index 2243c21758..3f446e2916 100644
--- a/src/libs/qtcreatorcdbext/qtcreatorcdbext.qbs
+++ b/src/libs/qtcreatorcdbext/qtcreatorcdbext.qbs
@@ -6,47 +6,9 @@ import qbs.Process
import qbs.Utilities
QtcLibrary {
- condition: qbs.toolchain.contains("msvc") && cdbPath
+ condition: qbs.toolchain.contains("msvc")
name: "qtcreatorcdbext"
targetName: name
- property string cdbPath: {
- var paths = [
- Environment.getEnv("CDB_PATH"),
- Environment.getEnv("ProgramFiles") + "/Debugging Tools For Windows/sdk",
- Environment.getEnv("ProgramFiles") + "/Debugging Tools For Windows (x86)/sdk",
- Environment.getEnv("ProgramFiles") + "/Debugging Tools For Windows (x64)/sdk",
- Environment.getEnv("ProgramFiles") + "/Debugging Tools For Windows 64-bit/sdk",
- Environment.getEnv("ProgramW6432") + "/Debugging Tools For Windows (x86)/sdk",
- Environment.getEnv("ProgramW6432") + "/Debugging Tools For Windows (x64)/sdk",
- Environment.getEnv("ProgramW6432") + "/Debugging Tools For Windows 64-bit/sdk",
- Environment.getEnv("ProgramFiles") + "/Windows Kits/8.0/Debuggers",
- Environment.getEnv("ProgramFiles") + "/Windows Kits/8.1/Debuggers",
- Environment.getEnv("ProgramFiles") + "/Windows Kits/10/Debuggers",
- Environment.getEnv("ProgramFiles(x86)") + "/Windows Kits/8.0/Debuggers/inc",
- Environment.getEnv("ProgramFiles(x86)") + "/Windows Kits/8.1/Debuggers/inc",
- Environment.getEnv("ProgramFiles(x86)") + "/Windows Kits/10/Debuggers/inc"
- ];
- var c = paths.length;
- for (var i = 0; i < c; ++i) {
- if (File.exists(paths[i])) {
- // The inc subdir is just used for detection. See qtcreatorcdbext.pro.
- return paths[i].endsWith("/inc") ? paths[i].substr(0, paths[i].length - 4)
- : paths[i];
- }
- }
- return undefined;
- }
- property string cdbLibPath: {
- var paths = qbs.architecture.contains("x86_64") ? ["x64", "amd64"] : ["x86", "i386"];
- var c = paths.length;
- for (var i = 0; i < c; ++i) {
- var libPath = FileInfo.joinPaths(cdbPath, "lib", paths[i]);
- if (File.exists(libPath)) {
- return libPath;
- }
- }
- return undefined;
- }
property string pythonInstallDir: Environment.getEnv("PYTHON_INSTALL_DIR")
@@ -127,13 +89,12 @@ QtcLibrary {
cpp.defines: ["WITH_PYTHON=1"]
}
cpp.includePaths: {
- var paths = [FileInfo.joinPaths(cdbPath, "inc")];
if (pythonDllProbe.found)
- paths.push(FileInfo.joinPaths(pythonInstallDir, "include"));
- return paths;
+ return [ FileInfo.joinPaths(pythonInstallDir, "include") ];
+ return [ ];
}
cpp.dynamicLibraries: {
- var libs = [ "user32.lib", FileInfo.joinPaths(cdbLibPath, "dbgeng.lib") ];
+ var libs = [ "user32.lib", "dbgeng.lib" ];
if (pythonDllProbe.found)
libs.push(FileInfo.joinPaths(pythonInstallDir, "libs",
pythonDllProbe.fileNamePrefix + ".lib"));
diff --git a/src/libs/utils/outputformatter.cpp b/src/libs/utils/outputformatter.cpp
index 49cb31d3e5..eb6e974dff 100644
--- a/src/libs/utils/outputformatter.cpp
+++ b/src/libs/utils/outputformatter.cpp
@@ -429,6 +429,7 @@ void OutputFormatter::append(const QString &text, const QTextCharFormat &format)
{
if (!plainTextEdit())
return;
+ flushTrailingNewline();
int startPos = 0;
int crPos = -1;
while ((crPos = text.indexOf('\r', startPos)) >= 0) {
@@ -437,7 +438,6 @@ void OutputFormatter::append(const QString &text, const QTextCharFormat &format)
d->cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
startPos = crPos + 1;
}
- flushTrailingNewline();
if (startPos < text.count())
d->cursor.insertText(text.mid(startPos), format);
}
diff --git a/src/plugins/autotest/boost/boosttestoutputreader.cpp b/src/plugins/autotest/boost/boosttestoutputreader.cpp
index 2fe0a1c928..84cd3e45a0 100644
--- a/src/plugins/autotest/boost/boosttestoutputreader.cpp
+++ b/src/plugins/autotest/boost/boosttestoutputreader.cpp
@@ -206,8 +206,6 @@ void BoostTestOutputReader::processOutputLine(const QByteArray &outputLine)
static QRegularExpression finish("^\\*{3} (\\d+) failure(s are| is) detected in the "
"test module \"(.*)\"$");
- static QRegularExpression errDetect("^\\*{3} Errors where detected in the "
- "test module \"(.*}\"; see standard output for details");
QString noErrors("*** No errors detected");
const QString line = removeCommandlineColors(QString::fromUtf8(outputLine));
@@ -340,8 +338,7 @@ void BoostTestOutputReader::processOutputLine(const QByteArray &outputLine)
BoostTestResult *result = new BoostTestResult(id(), m_projectFile, QString());
int failed = match.captured(1).toInt();
QString txt = tr("%1 failures detected in %2.").arg(failed).arg(match.captured(3));
- int passed = (m_testCaseCount != -1)
- ? m_testCaseCount - failed - m_summary[ResultType::Skip] : -1;
+ int passed = (m_testCaseCount != -1) ? m_testCaseCount - failed : -1;
if (m_testCaseCount != -1)
txt.append(' ').append(tr("%1 tests passed.").arg(passed));
result->setDescription(txt);
diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp
index 4581b91bd5..37fc75f464 100644
--- a/src/plugins/autotest/testrunner.cpp
+++ b/src/plugins/autotest/testrunner.cpp
@@ -268,7 +268,7 @@ void TestRunner::cancelCurrent(TestRunner::CancelReason reason)
void TestRunner::onProcessFinished()
{
- if (m_executingTests && QTC_GUARD(m_currentConfig)) {
+ if (m_executingTests && m_currentConfig) {
QTC_CHECK(m_fakeFutureInterface);
m_fakeFutureInterface->setProgressValue(m_fakeFutureInterface->progressValue()
+ m_currentConfig->testCaseCount());
@@ -286,13 +286,15 @@ void TestRunner::onProcessFinished()
}
}
}
- const int disabled = m_currentOutputReader->disabledTests();
- if (disabled > 0)
- emit hadDisabledTests(disabled);
- if (m_currentOutputReader->hasSummary())
- emit reportSummary(m_currentOutputReader->id(), m_currentOutputReader->summary());
+ if (m_currentOutputReader) {
+ const int disabled = m_currentOutputReader->disabledTests();
+ if (disabled > 0)
+ emit hadDisabledTests(disabled);
+ if (m_currentOutputReader->hasSummary())
+ emit reportSummary(m_currentOutputReader->id(), m_currentOutputReader->summary());
- m_currentOutputReader->resetCommandlineColor();
+ m_currentOutputReader->resetCommandlineColor();
+ }
resetInternalPointers();
if (!m_fakeFutureInterface) {
diff --git a/src/plugins/coreplugin/outputwindow.cpp b/src/plugins/coreplugin/outputwindow.cpp
index 9d58bae06a..80fb566698 100644
--- a/src/plugins/coreplugin/outputwindow.cpp
+++ b/src/plugins/coreplugin/outputwindow.cpp
@@ -590,7 +590,7 @@ class TestFormatterA : public OutputLineParser
private:
Result handleLine(const QString &text, OutputFormat) override
{
- static const QString replacement = "handled by A\n";
+ static const QString replacement = "handled by A";
if (m_handling) {
if (text.startsWith("A")) {
m_handling = false;
@@ -615,7 +615,7 @@ private:
Result handleLine(const QString &text, OutputFormat) override
{
if (text.startsWith("B"))
- return {Status::Done, {}, QString("handled by B\n")};
+ return {Status::Done, {}, QString("handled by B")};
return Status::NotHandled;
}
};
@@ -656,6 +656,7 @@ void Internal::CorePlugin::testOutputFormatter()
formatter.setLineParsers({new TestFormatterB, new TestFormatterA});
formatter.appendMessage(input.left(i), StdOutFormat);
formatter.appendMessage(input.mid(i), StdOutFormat);
+ formatter.flush();
QCOMPARE(textEdit.toPlainText(), output);
}
}
diff --git a/src/plugins/cppeditor/cppdoxygen_test.cpp b/src/plugins/cppeditor/cppdoxygen_test.cpp
index 59aad20d07..9fc6f1575c 100644
--- a/src/plugins/cppeditor/cppdoxygen_test.cpp
+++ b/src/plugins/cppeditor/cppdoxygen_test.cpp
@@ -204,11 +204,11 @@ void DoxygenTest::testBasic_data()
QTest::newRow("cpp_styleA_indented_preserve_mixed_indention_continuation") << _(
"\t bool preventFolding;\n"
- "\t /// \brief a|\n"
+ "\t /// \\brief a|\n"
"\t int a;\n"
) << _(
"\t bool preventFolding;\n"
- "\t /// \brief a\n"
+ "\t /// \\brief a\n"
"\t /// \n"
"\t int a;\n"
);
diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp
index 3b0a06c2b9..c7540e8ae1 100644
--- a/src/plugins/debugger/debuggerengine.cpp
+++ b/src/plugins/debugger/debuggerengine.cpp
@@ -1088,10 +1088,12 @@ void DebuggerEngine::gotoLocation(const Location &loc)
const QString file = loc.fileName().toString();
const int line = loc.lineNumber();
bool newEditor = false;
- IEditor *editor = EditorManager::openEditor(
- file, Id(),
- EditorManager::IgnoreNavigationHistory | EditorManager::DoNotSwitchToDesignMode,
- &newEditor);
+ IEditor *editor = EditorManager::openEditor(file,
+ Id(),
+ EditorManager::IgnoreNavigationHistory
+ | EditorManager::DoNotSwitchToDesignMode
+ | EditorManager::SwitchSplitIfAlreadyVisible,
+ &newEditor);
QTC_ASSERT(editor, return); // Unreadable file?
editor->gotoLine(line, 0, !boolSetting(StationaryEditorWhileStepping));
diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp
index 03e24ee3af..7f32733e1a 100644
--- a/src/plugins/projectexplorer/project.cpp
+++ b/src/plugins/projectexplorer/project.cpp
@@ -64,7 +64,6 @@
#include <QFileDialog>
#include <limits>
-#include <memory>
/*!
\class ProjectExplorer::Project
@@ -357,7 +356,8 @@ void Project::setNeedsInitialExpansion(bool needsExpansion)
d->m_needsInitialExpansion = needsExpansion;
}
-void Project::setExtraProjectFiles(const QSet<Utils::FilePath> &projectDocumentPaths)
+void Project::setExtraProjectFiles(const QSet<Utils::FilePath> &projectDocumentPaths,
+ const DocGenerator docGenerator)
{
QSet<Utils::FilePath> uniqueNewFiles = projectDocumentPaths;
uniqueNewFiles.remove(projectFilePath()); // Make sure to never add the main project file!
@@ -372,8 +372,14 @@ void Project::setExtraProjectFiles(const QSet<Utils::FilePath> &projectDocumentP
return toRemove.contains(d->filePath());
});
for (const Utils::FilePath &p : toAdd) {
- d->m_extraProjectDocuments.emplace_back(
- std::make_unique<ProjectDocument>(d->m_document->mimeType(), p, this));
+ if (docGenerator) {
+ std::unique_ptr<Core::IDocument> doc = docGenerator(p);
+ QTC_ASSERT(doc, continue);
+ d->m_extraProjectDocuments.push_back(std::move(doc));
+ } else {
+ d->m_extraProjectDocuments.emplace_back(std::make_unique<ProjectDocument>(
+ d->m_document->mimeType(), p, this));
+ }
}
}
@@ -802,6 +808,19 @@ bool Project::isKnownFile(const Utils::FilePath &filename) const
&element, nodeLessThan);
}
+const Node *Project::nodeForFilePath(const Utils::FilePath &filePath,
+ const Project::NodeMatcher &extraMatcher)
+{
+ const FileNode dummy(filePath, FileType::Unknown);
+ const auto range = std::equal_range(d->m_sortedNodeList.cbegin(), d->m_sortedNodeList.cend(),
+ &dummy, &nodeLessThan);
+ for (auto it = range.first; it != range.second; ++it) {
+ if ((*it)->filePath() == filePath && (!extraMatcher || extraMatcher(*it)))
+ return *it;
+ }
+ return nullptr;
+}
+
void Project::setProjectLanguages(Core::Context language)
{
if (d->m_projectLanguages == language)
diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h
index 8d12e4c15c..42fd4282c5 100644
--- a/src/plugins/projectexplorer/project.h
+++ b/src/plugins/projectexplorer/project.h
@@ -39,6 +39,7 @@
#include <QFileSystemModel>
#include <functional>
+#include <memory>
namespace Core { class Context; }
namespace Utils {
@@ -123,6 +124,8 @@ public:
Utils::FilePaths files(const NodeMatcher &matcher) const;
bool isKnownFile(const Utils::FilePath &filename) const;
+ const Node *nodeForFilePath(const Utils::FilePath &filePath,
+ const NodeMatcher &extraMatcher = {});
virtual QVariantMap toMap() const;
@@ -159,9 +162,11 @@ public:
void setRootProjectNode(std::unique_ptr<ProjectNode> &&root);
- // Set project files that will be watched and trigger the same callback
+ // Set project files that will be watched and by default trigger the same callback
// as the main project file.
- void setExtraProjectFiles(const QSet<Utils::FilePath> &projectDocumentPaths);
+ using DocGenerator = std::function<std::unique_ptr<Core::IDocument>(const Utils::FilePath &)>;
+ void setExtraProjectFiles(const QSet<Utils::FilePath> &projectDocumentPaths,
+ const DocGenerator docGenerator = {});
void setDisplayName(const QString &name);
void setProjectLanguage(Utils::Id id, bool enabled);
diff --git a/src/plugins/python/pythonrunconfiguration.cpp b/src/plugins/python/pythonrunconfiguration.cpp
index bed2621763..209d0906b2 100644
--- a/src/plugins/python/pythonrunconfiguration.cpp
+++ b/src/plugins/python/pythonrunconfiguration.cpp
@@ -281,6 +281,7 @@ PythonRunConfiguration::PythonRunConfiguration(Target *target, Utils::Id id)
const QString script = bti.targetFilePath.toUserOutput();
setDefaultDisplayName(tr("Run %1").arg(script));
scriptAspect->setValue(script);
+ aspect<WorkingDirectoryAspect>()->setDefaultWorkingDirectory(bti.targetFilePath.parentDir());
});
connect(target, &Target::buildSystemUpdated, this, &RunConfiguration::update);
@@ -298,9 +299,6 @@ void PythonRunConfiguration::updateLanguageServer()
PyLSConfigureAssistant::instance()->openDocumentWithPython(python, document);
}
}
-
- aspect<WorkingDirectoryAspect>()->setDefaultWorkingDirectory(
- Utils::FilePath::fromString(mainScript()).parentDir());
}
bool PythonRunConfiguration::supportsDebugger() const
diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp
index 6a18b68f8f..126ef39bcb 100644
--- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp
@@ -63,41 +63,6 @@ using namespace QmakeProjectManager::Internal;
using namespace QMakeInternal;
using namespace Utils;
-namespace {
-
-class QmakePriFileDocument : public Core::IDocument
-{
-public:
- QmakePriFileDocument(QmakePriFile *qmakePriFile, const Utils::FilePath &filePath) :
- IDocument(nullptr), m_priFile(qmakePriFile)
- {
- setId("Qmake.PriFile");
- setMimeType(QLatin1String(QmakeProjectManager::Constants::PROFILE_MIMETYPE));
- setFilePath(filePath);
- }
-
- ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const override
- {
- Q_UNUSED(state)
- Q_UNUSED(type)
- return BehaviorSilent;
- }
- bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override
- {
- Q_UNUSED(errorString)
- Q_UNUSED(flag)
- if (type == TypePermissions)
- return true;
- m_priFile->scheduleUpdate();
- return true;
- }
-
-private:
- QmakePriFile *m_priFile;
-};
-
-} // namespace
-
namespace QmakeProjectManager {
static Q_LOGGING_CATEGORY(qmakeParse, "qtc.qmake.parsing", QtWarningMsg);
diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp
index c421e7983a..7d22796d55 100644
--- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp
@@ -33,6 +33,7 @@
#include "qmakeprojectmanagerconstants.h"
#include "qmakestep.h"
+#include <coreplugin/documentmanager.h>
#include <coreplugin/icontext.h>
#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
@@ -97,6 +98,38 @@ static Q_LOGGING_CATEGORY(qmakeBuildSystemLog, "qtc.qmake.buildsystem", QtWarnin
<< msg; \
}
+class QmakePriFileDocument : public Core::IDocument
+{
+public:
+ QmakePriFileDocument(QmakePriFile *qmakePriFile, const Utils::FilePath &filePath) :
+ IDocument(nullptr), m_priFile(qmakePriFile)
+ {
+ setId("Qmake.PriFile");
+ setMimeType(QLatin1String(QmakeProjectManager::Constants::PROFILE_MIMETYPE));
+ setFilePath(filePath);
+ Core::DocumentManager::addDocument(this);
+ }
+
+ ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const override
+ {
+ Q_UNUSED(state)
+ Q_UNUSED(type)
+ return BehaviorSilent;
+ }
+ bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override
+ {
+ Q_UNUSED(errorString)
+ Q_UNUSED(flag)
+ if (type == TypePermissions)
+ return true;
+ m_priFile->scheduleUpdate();
+ return true;
+ }
+
+private:
+ QmakePriFile *m_priFile;
+};
+
/// Watches folders for QmakePriFile nodes
/// use one file system watcher to watch all folders
/// such minimizing system ressouce usage
@@ -266,8 +299,17 @@ void QmakeBuildSystem::updateDocuments()
QSet<FilePath> projectDocuments;
project()->rootProjectNode()->forEachProjectNode([&projectDocuments](const ProjectNode *n) {
projectDocuments.insert(n->filePath());
+
+ });
+ project()->setExtraProjectFiles(projectDocuments, [p = project()](const FilePath &fp)
+ -> std::unique_ptr<Core::IDocument> {
+ const Node * const n = p->nodeForFilePath(fp, [](const Node *n) {
+ return dynamic_cast<const QmakePriFileNode *>(n); });
+ QTC_ASSERT(n, return std::make_unique<Core::IDocument>());
+ QmakePriFile * const priFile = static_cast<const QmakePriFileNode *>(n)->priFile();
+ QTC_ASSERT(priFile, return std::make_unique<Core::IDocument>());
+ return std::make_unique<QmakePriFileDocument>(priFile, fp);
});
- project()->setExtraProjectFiles(projectDocuments);
}
void QmakeBuildSystem::updateCppCodeModel()
diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt
index cf5ee686bf..01809f2152 100644
--- a/src/plugins/qmldesigner/CMakeLists.txt
+++ b/src/plugins/qmldesigner/CMakeLists.txt
@@ -589,8 +589,11 @@ extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/bindingeditor
SOURCES bindingeditor.cpp bindingeditor.h
actioneditor.cpp actioneditor.h
+ abstracteditordialog.cpp abstracteditordialog.h
+ actioneditordialog.cpp actioneditordialog.h
bindingeditordialog.cpp bindingeditordialog.h
bindingeditorwidget.cpp bindingeditorwidget.h
+ connectionvisitor.cpp connectionvisitor.h
)
extend_qtc_plugin(QmlDesigner
diff --git a/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.cpp b/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.cpp
new file mode 100644
index 0000000000..872a004fcc
--- /dev/null
+++ b/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.cpp
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 "abstracteditordialog.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 <QPlainTextEdit>
+
+namespace QmlDesigner {
+
+AbstractEditorDialog::AbstractEditorDialog(QWidget *parent, const QString &title)
+ : QDialog(parent)
+ , m_titleString(title)
+{
+ setWindowFlag(Qt::Tool, true);
+ setWindowTitle(defaultTitle());
+ setModal(false);
+
+ setupJSEditor();
+ setupUIComponents();
+
+ QObject::connect(m_buttonBox, &QDialogButtonBox::accepted,
+ this, &AbstractEditorDialog::accepted);
+ QObject::connect(m_buttonBox, &QDialogButtonBox::rejected,
+ this, &AbstractEditorDialog::rejected);
+ QObject::connect(m_editorWidget, &BindingEditorWidget::returnKeyClicked,
+ this, &AbstractEditorDialog::accepted);
+ QObject::connect(m_editorWidget, &QPlainTextEdit::textChanged,
+ this, &AbstractEditorDialog::textChanged);
+}
+
+AbstractEditorDialog::~AbstractEditorDialog()
+{
+ delete m_editor; // m_editorWidget is handled by basetexteditor destructor
+ delete m_buttonBox;
+ delete m_comboBoxLayout;
+ delete m_verticalLayout;
+}
+
+void AbstractEditorDialog::showWidget()
+{
+ this->show();
+ this->raise();
+ m_editorWidget->setFocus();
+}
+
+void AbstractEditorDialog::showWidget(int x, int y)
+{
+ showWidget();
+ move(QPoint(x, y));
+}
+
+QString AbstractEditorDialog::editorValue() const
+{
+ if (!m_editorWidget)
+ return {};
+
+ return m_editorWidget->document()->toPlainText();
+}
+
+void AbstractEditorDialog::setEditorValue(const QString &text)
+{
+ if (m_editorWidget)
+ m_editorWidget->document()->setPlainText(text);
+}
+
+void AbstractEditorDialog::unregisterAutoCompletion()
+{
+ if (m_editorWidget)
+ m_editorWidget->unregisterAutoCompletion();
+}
+
+QString AbstractEditorDialog::defaultTitle() const
+{
+ return m_titleString;
+}
+
+void AbstractEditorDialog::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 AbstractEditorDialog::setupUIComponents()
+{
+ m_verticalLayout = new QVBoxLayout(this);
+
+ m_comboBoxLayout = new QHBoxLayout;
+
+ 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_verticalLayout->addLayout(m_comboBoxLayout);
+ m_verticalLayout->addWidget(m_editorWidget);
+ m_verticalLayout->addWidget(m_buttonBox);
+
+ this->resize(660, 240);
+}
+
+bool AbstractEditorDialog::isNumeric(const TypeName &type)
+{
+ static QList<TypeName> numericTypes = {"double", "int", "real"};
+ return numericTypes.contains(type);
+}
+
+bool AbstractEditorDialog::isColor(const TypeName &type)
+{
+ static QList<TypeName> colorTypes = {"QColor", "color"};
+ return colorTypes.contains(type);
+}
+
+bool AbstractEditorDialog::isVariant(const TypeName &type)
+{
+ static QList<TypeName> variantTypes = {"alias", "unknown", "variant", "var"};
+ return variantTypes.contains(type);
+}
+
+void AbstractEditorDialog::textChanged()
+{
+ if (m_lock)
+ return;
+
+ m_lock = true;
+ adjustProperties();
+ m_lock = false;
+}
+
+} // QmlDesigner namespace
diff --git a/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.h b/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.h
new file mode 100644
index 0000000000..ed8cdd0a13
--- /dev/null
+++ b/src/plugins/qmldesigner/components/bindingeditor/abstracteditordialog.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 ABSTRACTEDITORDIALOG_H
+#define ABSTRACTEDITORDIALOG_H
+
+#include <bindingeditor/bindingeditorwidget.h>
+#include <qmldesignercorelib_global.h>
+#include <texteditor/texteditor.h>
+
+#include <QDialog>
+
+QT_BEGIN_NAMESPACE
+class QDialogButtonBox;
+class QVBoxLayout;
+class QHBoxLayout;
+QT_END_NAMESPACE
+
+namespace QmlDesigner {
+
+class AbstractEditorDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ AbstractEditorDialog(QWidget *parent = nullptr, const QString &title = tr("Untitled Editor"));
+ ~AbstractEditorDialog() override;
+
+ void showWidget();
+ void showWidget(int x, int y);
+
+ QString editorValue() const;
+ void setEditorValue(const QString &text);
+
+ virtual void adjustProperties()= 0;
+
+ void unregisterAutoCompletion();
+
+ QString defaultTitle() const;
+
+ BindingEditorWidget *bindingEditorWidget() const
+ {
+ return m_editorWidget;
+ }
+
+protected:
+ void setupJSEditor();
+ void setupUIComponents();
+
+ static bool isNumeric(const TypeName &type);
+ static bool isColor(const TypeName &type);
+ static bool isVariant(const TypeName &type);
+
+public slots:
+ void textChanged();
+
+protected:
+ TextEditor::BaseTextEditor *m_editor = nullptr;
+ BindingEditorWidget *m_editorWidget = nullptr;
+ QVBoxLayout *m_verticalLayout = nullptr;
+ QDialogButtonBox *m_buttonBox = nullptr;
+ QHBoxLayout *m_comboBoxLayout = nullptr;
+ bool m_lock = false;
+ QString m_titleString;
+
+ const QString undefinedString = {"[Undefined]"};
+};
+
+}
+
+#endif //ABSTRACTEDITORDIALOG_H
diff --git a/src/plugins/qmldesigner/components/bindingeditor/actioneditor.cpp b/src/plugins/qmldesigner/components/bindingeditor/actioneditor.cpp
index ac86377816..486e33640d 100644
--- a/src/plugins/qmldesigner/components/bindingeditor/actioneditor.cpp
+++ b/src/plugins/qmldesigner/components/bindingeditor/actioneditor.cpp
@@ -28,6 +28,7 @@
#include <qmldesignerplugin.h>
#include <coreplugin/icore.h>
#include <coreplugin/actionmanager/actionmanager.h>
+#include <bindingeditor/actioneditordialog.h>
#include <metainfo.h>
#include <qmlmodelnodeproxy.h>
@@ -35,6 +36,14 @@
#include <nodelistproperty.h>
#include <propertyeditorvalue.h>
+#include <bindingproperty.h>
+#include <variantproperty.h>
+
+#include <qmljs/qmljsscopechain.h>
+#include <qmljs/qmljsvalueowner.h>
+
+static Q_LOGGING_CATEGORY(ceLog, "qtc.qmldesigner.connectioneditor", QtWarningMsg)
+
namespace QmlDesigner {
static ActionEditor *s_lastActionEditor = nullptr;
@@ -58,15 +67,14 @@ void ActionEditor::prepareDialog()
{
if (s_lastActionEditor)
s_lastActionEditor->hideWidget();
- s_lastActionEditor = this;
- m_dialog = new BindingEditorDialog(Core::ICore::dialogParent(),
- BindingEditorDialog::DialogType::ActionDialog);
+ s_lastActionEditor = this;
+ m_dialog = new ActionEditorDialog(Core::ICore::dialogParent());
- QObject::connect(m_dialog, &BindingEditorDialog::accepted,
+ QObject::connect(m_dialog, &AbstractEditorDialog::accepted,
this, &ActionEditor::accepted);
- QObject::connect(m_dialog, &BindingEditorDialog::rejected,
+ QObject::connect(m_dialog, &AbstractEditorDialog::rejected,
this, &ActionEditor::rejected);
m_dialog->setAttribute(Qt::WA_DeleteOnClose);
@@ -88,14 +96,14 @@ 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
+
+ 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
+QString ActionEditor::connectionValue() const
{
if (!m_dialog)
return {};
@@ -103,7 +111,7 @@ QString ActionEditor::bindingValue() const
return m_dialog->editorValue();
}
-void ActionEditor::setBindingValue(const QString &text)
+void ActionEditor::setConnectionValue(const QString &text)
{
if (m_dialog)
m_dialog->setEditorValue(text);
@@ -129,11 +137,160 @@ void ActionEditor::setModelIndex(const QModelIndex &index)
m_index = index;
}
+void ActionEditor::setModelNode(const ModelNode &modelNode)
+{
+ if (modelNode.isValid())
+ m_modelNode = modelNode;
+}
+
+bool isLiteral(QmlJS::AST::Node *ast)
+{
+ if (QmlJS::AST::cast<QmlJS::AST::StringLiteral *>(ast)
+ || QmlJS::AST::cast<QmlJS::AST::NumericLiteral *>(ast)
+ || QmlJS::AST::cast<QmlJS::AST::TrueLiteral *>(ast)
+ || QmlJS::AST::cast<QmlJS::AST::FalseLiteral *>(ast))
+ return true;
+ else
+ return false;
+}
+
+void ActionEditor::prepareConnections()
+{
+ if (!m_modelNode.isValid())
+ return;
+
+ BindingEditorWidget *bindingEditorWidget = m_dialog->bindingEditorWidget();
+
+ if (!bindingEditorWidget) {
+ qCInfo(ceLog) << Q_FUNC_INFO << "BindingEditorWidget is missing!";
+ return;
+ }
+
+ if (!bindingEditorWidget->qmlJsEditorDocument()) {
+ qCInfo(ceLog) << Q_FUNC_INFO << "QmlJsEditorDocument is missing!";
+ return;
+ }
+
+ // Prepare objects for analysing slots
+ const QmlJSTools::SemanticInfo &semanticInfo = bindingEditorWidget->qmljsdocument->semanticInfo();
+ const QList<QmlJS::AST::Node *> path = semanticInfo.rangePath(0);
+ const QmlJS::ContextPtr &context = semanticInfo.context;
+ const QmlJS::ScopeChain &scopeChain = semanticInfo.scopeChain(path);
+
+ static QList<TypeName> typeWhiteList({"string",
+ "real", "int", "double",
+ "bool",
+ "QColor", "color",
+ "QtQuick.Item", "QQuickItem"});
+
+ static QList<PropertyName> methodBlackList({"toString", "destroy"});
+
+ QList<ActionEditorDialog::ConnectionOption> connections;
+ QList<ActionEditorDialog::SingletonOption> singletons;
+ QStringList states;
+
+ const QList<QmlDesigner::ModelNode> allNodes = m_modelNode.view()->allModelNodes();
+ for (const auto &modelNode : allNodes) {
+ // Skip nodes without specified id
+ if (!modelNode.hasId())
+ continue;
+
+ ActionEditorDialog::ConnectionOption connection(modelNode.id());
+
+ for (const auto &propertyName : modelNode.metaInfo().propertyNames()) {
+ if (!typeWhiteList.contains(modelNode.metaInfo().propertyTypeName(propertyName)))
+ continue;
+
+ const QString name = QString::fromUtf8(propertyName);
+ TypeName type = modelNode.metaInfo().propertyTypeName(propertyName);
+ if (type.contains("<cpp>."))
+ type.remove(0, 6);
+
+ connection.properties.append(ActionEditorDialog::PropertyOption(name, type));
+ }
+
+ for (const VariantProperty &variantProperty : modelNode.variantProperties()) {
+ if (variantProperty.isValid()) {
+ if (variantProperty.isDynamic()) {
+ if (!typeWhiteList.contains(variantProperty.dynamicTypeName()))
+ continue;
+
+ const QString name = QString::fromUtf8(variantProperty.name());
+ TypeName type = variantProperty.dynamicTypeName();
+ if (type.contains("<cpp>."))
+ type.remove(0, 6);
+
+ connection.properties.append(ActionEditorDialog::PropertyOption(name, type));
+ }
+ }
+ }
+
+ for (const auto &slotName : modelNode.metaInfo().slotNames()) {
+ QmlJS::Document::MutablePtr newDoc = QmlJS::Document::create(
+ QLatin1String("<expression>"), QmlJS::Dialect::JavaScript);
+ newDoc->setSource(QLatin1String(slotName));
+ newDoc->parseExpression();
+
+ QmlJS::AST::ExpressionNode *expression = newDoc->expression();
+
+ if (expression && !isLiteral(expression)) {
+ QmlJS::ValueOwner *interp = context->valueOwner();
+ const QmlJS::Value *value = interp->convertToObject(scopeChain.evaluate(expression));
+
+ if (const QmlJS::FunctionValue *f = value->asFunctionValue()) {
+ // Only add slots with zero arguments
+ if (f->namedArgumentCount() == 0 && !methodBlackList.contains(slotName))
+ connection.methods.append(QString::fromUtf8(slotName));
+ }
+ }
+ }
+
+ connection.methods.removeDuplicates();
+ connections.append(connection);
+ }
+
+ // Singletons
+ if (RewriterView *rv = m_modelNode.view()->rewriterView()) {
+ for (const QmlTypeData &data : rv->getQMLTypes()) {
+ if (!data.typeName.isEmpty()) {
+ NodeMetaInfo metaInfo = m_modelNode.view()->model()->metaInfo(data.typeName.toUtf8());
+ if (metaInfo.isValid()) {
+ ActionEditorDialog::SingletonOption singelton;
+ for (const PropertyName &propertyName : metaInfo.propertyNames()) {
+ TypeName type = metaInfo.propertyTypeName(propertyName);
+
+ if (!typeWhiteList.contains(type))
+ continue;
+
+ const QString name = QString::fromUtf8(propertyName);
+ if (type.contains("<cpp>."))
+ type.remove(0, 6);
+
+ singelton.properties.append(ActionEditorDialog::PropertyOption(name, type));
+ }
+
+ if (!singelton.properties.isEmpty()) {
+ singelton.item = data.typeName;
+ singletons.append(singelton);
+ }
+ }
+ }
+ }
+ }
+
+ // States
+ for (const QmlModelState &state : QmlItemNode(m_modelNode).states().allStates())
+ states.append(state.name());
+
+
+ if (!connections.isEmpty() && !m_dialog.isNull())
+ m_dialog->setAllConnections(connections, singletons, states);
+}
+
void ActionEditor::updateWindowName()
{
- if (!m_dialog.isNull())
- {
- m_dialog->setWindowTitle(tr("Connection Editor"));
+ if (!m_dialog.isNull()) {
+ m_dialog->setWindowTitle(m_dialog->defaultTitle());
m_dialog->raise();
}
}
diff --git a/src/plugins/qmldesigner/components/bindingeditor/actioneditor.h b/src/plugins/qmldesigner/components/bindingeditor/actioneditor.h
index 7c53dffb60..c0356e81c4 100644
--- a/src/plugins/qmldesigner/components/bindingeditor/actioneditor.h
+++ b/src/plugins/qmldesigner/components/bindingeditor/actioneditor.h
@@ -26,7 +26,7 @@
#ifndef ACTIONEDITOR_H
#define ACTIONEDITOR_H
-#include <bindingeditor/bindingeditordialog.h>
+#include <bindingeditor/actioneditordialog.h>
#include <qmldesignercorelib_global.h>
#include <modelnode.h>
@@ -40,7 +40,7 @@ class ActionEditor : public QObject
{
Q_OBJECT
- Q_PROPERTY(QString text READ bindingValue WRITE setBindingValue)
+ Q_PROPERTY(QString text READ connectionValue WRITE setConnectionValue)
public:
ActionEditor(QObject *parent = nullptr);
@@ -52,14 +52,18 @@ public:
Q_INVOKABLE void showWidget(int x, int y);
Q_INVOKABLE void hideWidget();
- QString bindingValue() const;
- void setBindingValue(const QString &text);
+ QString connectionValue() const;
+ void setConnectionValue(const QString &text);
bool hasModelIndex() const;
void resetModelIndex();
QModelIndex modelIndex() const;
void setModelIndex(const QModelIndex &index);
+ void setModelNode(const ModelNode &modelNode);
+
+ void prepareConnections();
+
Q_INVOKABLE void updateWindowName();
signals:
@@ -67,14 +71,12 @@ signals:
void rejected();
private:
- QVariant backendValue() const;
- QVariant modelNodeBackend() const;
- QVariant stateModelNode() const;
void prepareDialog();
private:
- QPointer<BindingEditorDialog> m_dialog;
+ QPointer<ActionEditorDialog> m_dialog;
QModelIndex m_index;
+ QmlDesigner::ModelNode m_modelNode;
};
}
diff --git a/src/plugins/qmldesigner/components/bindingeditor/actioneditordialog.cpp b/src/plugins/qmldesigner/components/bindingeditor/actioneditordialog.cpp
new file mode 100644
index 0000000000..bcd99de716
--- /dev/null
+++ b/src/plugins/qmldesigner/components/bindingeditor/actioneditordialog.cpp
@@ -0,0 +1,656 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 "actioneditordialog.h"
+
+#include "connectionvisitor.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 <QHBoxLayout>
+#include <QComboBox>
+#include <QPlainTextEdit>
+
+static Q_LOGGING_CATEGORY(ceLog, "qtc.qmldesigner.connectioneditor", QtWarningMsg)
+
+namespace QmlDesigner {
+
+ActionEditorDialog::ActionEditorDialog(QWidget *parent)
+ : AbstractEditorDialog(parent, tr("Connection Editor"))
+{
+ setupUIComponents();
+
+ QObject::connect(m_comboBoxType, QOverload<int>::of(&QComboBox::activated),
+ [this] (int idx) { this->updateComboBoxes(idx, ComboBox::Type); });
+
+ // Action connections
+ QObject::connect(m_actionTargetItem, QOverload<int>::of(&QComboBox::activated),
+ [this] (int idx) { this->updateComboBoxes(idx, ComboBox::TargetItem); });
+ QObject::connect(m_actionMethod, QOverload<int>::of(&QComboBox::activated),
+ [this] (int idx) { this->updateComboBoxes(idx, ComboBox::TargetProperty); });
+
+ // Assignment connections
+ QObject::connect(m_assignmentTargetItem, QOverload<int>::of(&QComboBox::activated),
+ [this] (int idx) { this->updateComboBoxes(idx, ComboBox::TargetItem); });
+ QObject::connect(m_assignmentTargetProperty, QOverload<int>::of(&QComboBox::activated),
+ [this] (int idx) { this->updateComboBoxes(idx, ComboBox::TargetProperty); });
+ QObject::connect(m_assignmentSourceItem, QOverload<int>::of(&QComboBox::activated),
+ [this] (int idx) { this->updateComboBoxes(idx, ComboBox::SourceItem); });
+ QObject::connect(m_assignmentSourceProperty, QOverload<int>::of(&QComboBox::activated),
+ [this] (int idx) { this->updateComboBoxes(idx, ComboBox::SourceProperty); });
+}
+
+ActionEditorDialog::~ActionEditorDialog()
+{
+}
+
+void ActionEditorDialog::adjustProperties()
+{
+ // Analyze the current connection editor statement/expression
+ const auto qmlJSDocument = bindingEditorWidget()->qmlJsEditorDocument();
+ auto doc = QmlJS::Document::create(QLatin1String("<expression>"), QmlJS::Dialect::JavaScript);
+ doc->setSource(qmlJSDocument->plainText());
+ bool parseResult = doc->parseExpression();
+
+ if (!parseResult) {
+ qCInfo(ceLog) << Q_FUNC_INFO << "Couldn't parse the expression!";
+ return;
+ }
+
+ auto astNode = doc->ast();
+ if (!astNode) {
+ qCInfo(ceLog) << Q_FUNC_INFO << "There was no AST::Node in the document!";
+ return;
+ }
+
+ ConnectionVisitor qmlVisitor;
+ QmlJS::AST::Node::accept(astNode, &qmlVisitor);
+
+ const auto expression = qmlVisitor.expression();
+
+ if (expression.isEmpty()) {
+ // Set all ComboBoxes to [Undefined], add connections to target item ComboBox
+ fillAndSetTargetItem(undefinedString);
+ fillAndSetTargetProperty(undefinedString);
+ fillAndSetSourceItem(undefinedString);
+ fillAndSetSourceProperty(undefinedString);
+ return;
+ }
+
+ bool typeDone = false;
+ bool targetDone = false;
+
+ for (int i = 0; i < expression.count(); ++i) {
+ switch (expression[i].first) {
+
+ case QmlJS::AST::Node::Kind::Kind_CallExpression:
+ {
+ setType(ConnectionType::Action);
+ typeDone = true;
+ }
+ break;
+
+ case QmlJS::AST::Node::Kind::Kind_BinaryExpression:
+ {
+ setType(ConnectionType::Assignment);
+ typeDone = true;
+ }
+ break;
+
+ case QmlJS::AST::Node::Kind::Kind_FieldMemberExpression:
+ {
+ QString fieldMember = expression[i].second;
+ ++i;// Increment index to get IdentifierExpression or next FieldMemberExpression
+ while (expression[i].first == QmlJS::AST::Node::Kind::Kind_FieldMemberExpression) {
+ fieldMember.prepend(expression[i].second + ".");
+ ++i; // Increment index to get IdentifierExpression
+ }
+
+ if (targetDone && m_comboBoxType->currentIndex() != ConnectionType::Action) {
+ fillAndSetSourceItem(expression[i].second);
+ fillAndSetSourceProperty(fieldMember);
+ } else {
+ if (typeDone) {
+ fillAndSetTargetItem(expression[i].second);
+ fillAndSetTargetProperty(fieldMember);
+ } else { // e.g. 'element.width'
+ // In this case Assignment is more likley
+ setType(ConnectionType::Assignment);
+ fillAndSetTargetItem(expression[i].second);
+ fillAndSetTargetProperty(fieldMember);
+ fillAndSetSourceItem(undefinedString);
+ fillAndSetSourceProperty(undefinedString);
+ }
+ targetDone = true;
+ }
+
+ }
+ break;
+
+ case QmlJS::AST::Node::Kind::Kind_TrueLiteral:
+ case QmlJS::AST::Node::Kind::Kind_FalseLiteral:
+ case QmlJS::AST::Node::Kind::Kind_NumericLiteral:
+ case QmlJS::AST::Node::Kind::Kind_StringLiteral:
+ {
+ if (targetDone) {
+ fillAndSetSourceItem(undefinedString);
+ fillAndSetSourceProperty(expression[i].second, expression[i].first);
+ } else {
+ // In this case Assignment is more likley
+ setType(ConnectionType::Assignment);
+ fillAndSetTargetItem(undefinedString);
+ fillAndSetTargetProperty(undefinedString);
+ fillAndSetSourceItem(undefinedString);
+ fillAndSetSourceProperty(expression[i].second, expression[i].first);
+ }
+ }
+ break;
+
+ case QmlJS::AST::Node::Kind::Kind_IdentifierExpression:
+ {
+ if (typeDone) {
+ if (m_comboBoxType->currentIndex() == ConnectionType::Assignment) { // e.g. 'element = rectangle
+ if (targetDone) {
+ fillAndSetSourceItem(undefinedString);
+ fillAndSetSourceProperty(undefinedString);
+ } else {
+ fillAndSetTargetItem(expression[i].second);
+ fillAndSetTargetProperty(undefinedString);
+ targetDone = true;
+ }
+ } else { // e.g. 'print("blabla")'
+ fillAndSetTargetItem(undefinedString);
+ fillAndSetTargetProperty(undefinedString);
+ targetDone = true;
+ }
+ } else { // e.g. 'element'
+ // In this case Assignment is more likley
+ setType(ConnectionType::Assignment);
+ fillAndSetTargetItem(expression[i].second);
+ fillAndSetTargetProperty(undefinedString);
+ fillAndSetSourceItem(undefinedString);
+ fillAndSetSourceProperty(undefinedString);
+ }
+ }
+ break;
+
+ default:
+ {
+ fillAndSetTargetItem(undefinedString);
+ fillAndSetTargetProperty(undefinedString);
+ fillAndSetSourceItem(undefinedString);
+ fillAndSetSourceProperty(undefinedString);
+ }
+ break;
+ }
+ }
+}
+
+void ActionEditorDialog::setAllConnections(const QList<ConnectionOption> &connections,
+ const QList<SingletonOption> &singletons,
+ const QStringList &states)
+{
+ m_lock = true;
+
+ m_connections = connections;
+ m_singletons = singletons;
+ m_states = states;
+ adjustProperties();
+
+ m_lock = false;
+}
+
+void ActionEditorDialog::updateComboBoxes(int index, ComboBox type)
+{
+ Q_UNUSED(index)
+
+ const int currentType = m_comboBoxType->currentIndex();
+ const int currentStack = m_stackedLayout->currentIndex();
+ bool typeChanged = false;
+
+ if (type == ComboBox::Type) {
+ if (currentType != currentStack)
+ typeChanged = true;
+ else
+ return; // Prevent rebuild of expression if type didn't change
+ }
+
+ if (typeChanged) {
+ m_stackedLayout->setCurrentIndex(currentType);
+ if (currentStack == ConnectionType::Action) {
+ // Previous type was Action
+ const auto targetItem = m_actionTargetItem->currentText();
+ fillAndSetTargetItem(targetItem, true);
+ fillAndSetTargetProperty(QString(), true);
+ fillAndSetSourceItem(QString(), true);
+ fillAndSetSourceProperty(QString(), QmlJS::AST::Node::Kind::Kind_Undefined, true);
+ } else {
+ // Previous type was Assignment
+ const auto targetItem = m_assignmentTargetItem->currentText();
+ fillAndSetTargetItem(targetItem, true);
+ fillAndSetTargetProperty(QString(), true);
+ }
+ } else {
+ if (currentType == ConnectionType::Action) {
+ // Prevent rebuild of expression if undefinedString item was selected
+ switch (type) {
+ case ComboBox::TargetItem:
+ if (m_actionTargetItem->currentText() == undefinedString)
+ return;
+ break;
+ case ComboBox::TargetProperty:
+ if (m_actionMethod->currentText() == undefinedString)
+ return;
+ break;
+ default:
+ break;
+ }
+
+ fillAndSetTargetItem(m_actionTargetItem->currentText());
+ fillAndSetTargetProperty(m_actionMethod->currentText(), true);
+ } else { // ConnectionType::Assignment
+ const auto targetItem = m_assignmentTargetItem->currentText();
+ const auto targetProperty = m_assignmentTargetProperty->currentText();
+ const auto sourceItem = m_assignmentSourceItem->currentText();
+ const auto sourceProperty = m_assignmentSourceProperty->currentText();
+
+ // Prevent rebuild of expression if undefinedString item was selected
+ switch (type) {
+ case ComboBox::TargetItem:
+ if (targetItem == undefinedString)
+ return;
+ break;
+ case ComboBox::TargetProperty:
+ if (targetProperty == undefinedString)
+ return;
+ break;
+ case ComboBox::SourceItem:
+ if (sourceItem == undefinedString)
+ return;
+ break;
+ case ComboBox::SourceProperty:
+ if (sourceProperty == undefinedString)
+ return;
+ break;
+ default:
+ break;
+ }
+
+ fillAndSetTargetItem(targetItem, true);
+ fillAndSetTargetProperty(targetProperty, true);
+
+ const auto sourcePropertyType = m_assignmentSourceProperty->currentData().value<TypeName>();
+
+ if (type == ComboBox::SourceItem) {
+ fillAndSetSourceItem(sourceItem, true);
+
+ if (sourcePropertyType == specificItem)
+ fillAndSetSourceProperty(QString(),
+ QmlJS::AST::Node::Kind::Kind_Undefined,
+ true);
+ else
+ fillAndSetSourceProperty(sourceProperty,
+ QmlJS::AST::Node::Kind::Kind_Undefined,
+ true);
+ } else if (type == ComboBox::SourceProperty) {
+ if (sourcePropertyType == specificItem) {
+ fillAndSetSourceItem(QString(), false);
+ fillAndSetSourceProperty(sourceProperty,
+ QmlJS::AST::Node::Kind::Kind_StringLiteral,
+ false);
+ } else {
+ fillAndSetSourceProperty(sourceProperty);
+ }
+ } else {
+ if (sourcePropertyType == specificItem) {
+ fillAndSetSourceItem(QString(), false);
+ fillAndSetSourceProperty(sourceProperty,
+ QmlJS::AST::Node::Kind::Kind_StringLiteral,
+ false);
+ } else {
+ fillAndSetSourceItem(sourceItem, true);
+ fillAndSetSourceProperty(sourceProperty,
+ QmlJS::AST::Node::Kind::Kind_Undefined,
+ true);
+ }
+ }
+ }
+ }
+
+ // Compose expression
+ QString value;
+ if (currentType == ConnectionType::Action) {
+ const auto targetItem = m_actionTargetItem->currentText();
+ const auto method = m_actionMethod->currentText();
+
+ if (targetItem != undefinedString && method != undefinedString){
+ value = targetItem + "." + method + "()";
+ } else if (targetItem != undefinedString && method == undefinedString) {
+ value = targetItem;
+ }
+ } else { // ConnectionType::Assignment
+ const auto targetItem = m_assignmentTargetItem->currentText();
+ const auto targetProperty = m_assignmentTargetProperty->currentText();
+ const auto sourceItem = m_assignmentSourceItem->currentText();
+ const auto sourceProperty = m_assignmentSourceProperty->currentText();
+
+ QString lhs;
+
+ if (targetItem != undefinedString && targetProperty != undefinedString) {
+ lhs = targetItem + "." + targetProperty;
+ } else if (targetItem != undefinedString && targetProperty == undefinedString) {
+ lhs = targetItem;
+ }
+
+ QString rhs;
+
+ if (sourceItem != undefinedString && sourceProperty != undefinedString) {
+ rhs = sourceItem + "." + sourceProperty;
+ } else if (sourceItem != undefinedString && sourceProperty == undefinedString) {
+ rhs = sourceItem;
+ } else if (sourceItem == undefinedString && sourceProperty != undefinedString) {
+ const QString data = m_assignmentTargetProperty->currentData().toString();
+ if (data == "string") {
+ rhs = "\"" + sourceProperty + "\"";
+ } else {
+ rhs = sourceProperty;
+ }
+ }
+
+ if (!lhs.isEmpty() && !rhs.isEmpty()) {
+ value = lhs + " = " + rhs;
+ } else {
+ value = lhs + rhs;
+ }
+ }
+
+ {
+ const QSignalBlocker blocker(m_editorWidget);
+ setEditorValue(value);
+ }
+}
+
+void ActionEditorDialog::setupUIComponents()
+{
+ m_comboBoxType = new QComboBox(this);
+
+ QMetaEnum metaEnum = QMetaEnum::fromType<ConnectionType>();
+ for (int i = 0; i != metaEnum.keyCount(); ++i) {
+ const char *key = QMetaEnum::fromType<ConnectionType>().valueToKey(i);
+ m_comboBoxType->addItem(QString::fromLatin1(key));
+ }
+
+ m_comboBoxLayout->addWidget(m_comboBoxType);
+
+ m_stackedLayout = new QStackedLayout();
+
+ m_actionLayout = new QHBoxLayout();
+ m_assignmentLayout = new QHBoxLayout();
+
+ m_actionPlaceholder = new QWidget(this);
+ m_actionPlaceholder->setLayout(m_actionLayout);
+
+ m_assignmentPlaceholder = new QWidget(this);
+ m_assignmentPlaceholder->setLayout(m_assignmentLayout);
+
+ // Setup action ComboBoxes
+ m_actionTargetItem = new QComboBox(this);
+ m_actionMethod = new QComboBox(this);
+ m_actionLayout->addWidget(m_actionTargetItem);
+ m_actionLayout->addWidget(m_actionMethod);
+
+ // Setup assignment ComboBoxes
+ m_assignmentTargetItem = new QComboBox(this);
+ m_assignmentTargetProperty = new QComboBox(this);
+ m_assignmentSourceItem = new QComboBox(this);
+ m_assignmentSourceProperty = new QComboBox(this);
+ m_assignmentLayout->addWidget(m_assignmentTargetItem);
+ m_assignmentLayout->addWidget(m_assignmentTargetProperty);
+ m_assignmentLayout->addWidget(m_assignmentSourceItem);
+ m_assignmentLayout->addWidget(m_assignmentSourceProperty);
+
+ m_stackedLayout->addWidget(m_actionPlaceholder);
+ m_stackedLayout->addWidget(m_assignmentPlaceholder);
+
+ m_comboBoxLayout->addItem(m_stackedLayout);
+
+ this->resize(720, 240);
+}
+
+void ActionEditorDialog::setType(ConnectionType type)
+{
+ m_comboBoxType->setCurrentIndex(type);
+ m_stackedLayout->setCurrentIndex(type);
+}
+
+void ActionEditorDialog::fillAndSetTargetItem(const QString &value, bool useDefault)
+{
+ if (m_comboBoxType->currentIndex() == ConnectionType::Action) {
+ m_actionTargetItem->clear();
+ for (const auto &connection : m_connections) {
+ if (!connection.methods.isEmpty())
+ m_actionTargetItem->addItem(connection.item);
+ }
+
+ if (m_actionTargetItem->findText(value) != -1) {
+ m_actionTargetItem->setCurrentText(value);
+ } else {
+ if (useDefault && m_actionTargetItem->count())
+ m_actionTargetItem->setCurrentIndex(0);
+ else
+ insertAndSetUndefined(m_actionTargetItem);
+ }
+ } else { // ConnectionType::Assignment
+ m_assignmentTargetItem->clear();
+ for (const auto &connection : m_connections) {
+ if (!connection.properties.isEmpty())
+ m_assignmentTargetItem->addItem(connection.item);
+ }
+
+ if (m_assignmentTargetItem->findText(value) != -1) {
+ m_assignmentTargetItem->setCurrentText(value);
+ } else {
+ if (useDefault && m_actionTargetItem->count())
+ m_actionTargetItem->setCurrentIndex(0);
+ else
+ insertAndSetUndefined(m_assignmentTargetItem);
+ }
+ }
+}
+
+void ActionEditorDialog::fillAndSetTargetProperty(const QString &value, bool useDefault)
+{
+ if (m_comboBoxType->currentIndex() == ConnectionType::Action) {
+ m_actionMethod->clear();
+ const QString targetItem = m_actionTargetItem->currentText();
+ const int idx = m_connections.indexOf(targetItem);
+
+ if (idx == -1) {
+ insertAndSetUndefined(m_actionMethod);
+ } else {
+ m_actionMethod->addItems(m_connections[idx].methods);
+
+ if (m_actionMethod->findText(value) != -1) {
+ m_actionMethod->setCurrentText(value);
+ } else {
+ if (useDefault && m_actionMethod->count())
+ m_actionMethod->setCurrentIndex(0);
+ else
+ insertAndSetUndefined(m_actionMethod);
+ }
+ }
+ } else { // ConnectionType::Assignment
+ m_assignmentTargetProperty->clear();
+ const QString targetItem = m_assignmentTargetItem->currentText();
+ const int idx = m_connections.indexOf(targetItem);
+
+ if (idx == -1) {
+ insertAndSetUndefined(m_assignmentTargetProperty);
+ } else {
+ for (const auto &property : m_connections[idx].properties)
+ m_assignmentTargetProperty->addItem(property.name, property.type);
+
+ if (m_assignmentTargetProperty->findText(value) != -1) {
+ m_assignmentTargetProperty->setCurrentText(value);
+ } else {
+ if (useDefault && m_assignmentTargetProperty->count())
+ m_assignmentTargetProperty->setCurrentIndex(0);
+ else
+ insertAndSetUndefined(m_assignmentTargetProperty);
+ }
+ }
+ }
+}
+
+void ActionEditorDialog::fillAndSetSourceItem(const QString &value, bool useDefault)
+{
+ m_assignmentSourceItem->clear();
+ const TypeName targetPropertyType = m_assignmentTargetProperty->currentData().value<TypeName>();
+
+ if (!targetPropertyType.isEmpty()) {
+ for (const ConnectionOption &connection : m_connections) {
+ if (!connection.containsType(targetPropertyType))
+ continue;
+
+ m_assignmentSourceItem->addItem(connection.item);
+ }
+
+ // Add Constants
+ for (const SingletonOption &singleton : m_singletons) {
+ if (!singleton.containsType(targetPropertyType))
+ continue;
+
+ m_assignmentSourceItem->addItem(singleton.item, singletonItem);
+ }
+ }
+
+ if (m_assignmentSourceItem->findText(value) != -1) {
+ m_assignmentSourceItem->setCurrentText(value);
+ } else {
+ if (useDefault && m_assignmentSourceItem->count())
+ m_assignmentSourceItem->setCurrentIndex(0);
+ else
+ insertAndSetUndefined(m_assignmentSourceItem);
+ }
+}
+
+void ActionEditorDialog::fillAndSetSourceProperty(const QString &value,
+ QmlJS::AST::Node::Kind kind,
+ bool useDefault)
+{
+ m_assignmentSourceProperty->clear();
+ const TypeName targetPropertyType = m_assignmentTargetProperty->currentData().value<TypeName>();
+ const QString targetProperty = m_assignmentTargetProperty->currentText();
+
+ if (kind != QmlJS::AST::Node::Kind::Kind_Undefined) {
+ if (targetPropertyType == "bool") {
+ m_assignmentSourceProperty->addItem("true", specificItem);
+ m_assignmentSourceProperty->addItem("false", specificItem);
+
+ if (m_assignmentSourceProperty->findText(value) != -1)
+ m_assignmentSourceProperty->setCurrentText(value);
+ else
+ insertAndSetUndefined(m_assignmentSourceProperty);
+ } else if (targetProperty == "state") {
+ for (const auto &state : m_states)
+ m_assignmentSourceProperty->addItem(state, specificItem);
+
+ if (m_assignmentSourceProperty->findText(value) != -1)
+ m_assignmentSourceProperty->setCurrentText(value);
+ else
+ insertAndSetUndefined(m_assignmentSourceProperty);
+ } else {
+ m_assignmentSourceProperty->insertItem(0, value, specificItem);
+ m_assignmentSourceProperty->setCurrentIndex(0);
+ }
+
+ } else {
+ const TypeName sourceItemType = m_assignmentSourceItem->currentData().value<TypeName>();
+ const QString sourceItem = m_assignmentSourceItem->currentText();
+ // We need to distinguish between singleton (Constants) and standard item
+ const int idx = (sourceItemType == singletonItem) ? m_singletons.indexOf(sourceItem)
+ : m_connections.indexOf(sourceItem);
+
+ if (idx == -1) {
+ insertAndSetUndefined(m_assignmentSourceProperty);
+ } else {
+ int specificsEnd = -1;
+ // Add type specific items
+ if (targetPropertyType == "bool") {
+ m_assignmentSourceProperty->addItem("true", specificItem);
+ m_assignmentSourceProperty->addItem("false", specificItem);
+ specificsEnd = 2;
+ } else if (targetProperty == "state") {
+ for (const auto &state : m_states)
+ m_assignmentSourceProperty->addItem(state, specificItem);
+
+ specificsEnd = m_states.count();
+ }
+
+ if (specificsEnd != -1)
+ m_assignmentSourceProperty->insertSeparator(specificsEnd);
+
+ if (sourceItemType == singletonItem) {
+ for (const auto &property : m_singletons[idx].properties) {
+ if (targetPropertyType.isEmpty() // TODO isEmpty correct?!
+ || property.type == targetPropertyType
+ || (isNumeric(property.type) && isNumeric(targetPropertyType)))
+ m_assignmentSourceProperty->addItem(property.name, property.type);
+ }
+ } else {
+ for (const auto &property : m_connections[idx].properties) {
+ if (targetPropertyType.isEmpty() // TODO isEmpty correct?!
+ || property.type == targetPropertyType
+ || (isNumeric(property.type) && isNumeric(targetPropertyType)))
+ m_assignmentSourceProperty->addItem(property.name, property.type);
+ }
+ }
+
+ if (m_assignmentSourceProperty->findText(value) != -1 && !value.isEmpty()) {
+ m_assignmentSourceProperty->setCurrentText(value);
+ } else {
+ if (useDefault && m_assignmentSourceProperty->count())
+ m_assignmentSourceProperty->setCurrentIndex(specificsEnd + 1);
+ else
+ insertAndSetUndefined(m_assignmentSourceProperty);
+ }
+ }
+ }
+}
+
+void ActionEditorDialog::insertAndSetUndefined(QComboBox *comboBox)
+{
+ comboBox->insertItem(0, undefinedString);
+ comboBox->setCurrentIndex(0);
+}
+
+} // QmlDesigner namespace
diff --git a/src/plugins/qmldesigner/components/bindingeditor/actioneditordialog.h b/src/plugins/qmldesigner/components/bindingeditor/actioneditordialog.h
new file mode 100644
index 0000000000..e19c7fe657
--- /dev/null
+++ b/src/plugins/qmldesigner/components/bindingeditor/actioneditordialog.h
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 ACTIONEDITORDIALOG_H
+#define ACTIONEDITORDIALOG_H
+
+#include <bindingeditor/abstracteditordialog.h>
+#include <qmljs/parser/qmljsast_p.h>
+
+#include <QStackedLayout>
+
+QT_BEGIN_NAMESPACE
+class QComboBox;
+QT_END_NAMESPACE
+
+namespace QmlDesigner {
+
+class ActionEditorDialog : public AbstractEditorDialog
+{
+ Q_OBJECT
+
+public:
+ enum ConnectionType { Action, Assignment };
+ Q_ENUM(ConnectionType)
+
+ enum ComboBox { Type, TargetItem, TargetProperty, SourceItem, SourceProperty };
+ Q_ENUM(ComboBox)
+
+ class PropertyOption
+ {
+ public:
+ PropertyOption() {}
+ PropertyOption(const QString &n, const TypeName &t)
+ : name(n)
+ , type(t)
+ {}
+
+ bool operator==(const QString &value) const { return value == name; }
+ bool operator==(const PropertyOption &value) const { return value.name == name; }
+
+ QString name;
+ TypeName type;
+ };
+
+ class SingletonOption
+ {
+ public:
+ SingletonOption() {}
+ SingletonOption(const QString &value) { item = value; }
+
+ bool containsType(const TypeName &t) const
+ {
+ for (const auto &p : properties) {
+ if (t == p.type || (isNumeric(t) && isNumeric(p.type)))
+ return true;
+ }
+
+ return false;
+ }
+
+ bool operator==(const QString &value) const { return value == item; }
+ bool operator==(const SingletonOption &value) const { return value.item == item; }
+
+ QString item;
+ QList<PropertyOption> properties;
+ };
+
+ class ConnectionOption : public SingletonOption
+ {
+ public:
+ ConnectionOption() {}
+ ConnectionOption(const QString &value) : SingletonOption(value) {}
+
+ QStringList methods;
+ };
+
+
+ ActionEditorDialog(QWidget *parent = nullptr);
+ ~ActionEditorDialog() override;
+
+ void adjustProperties() override;
+
+ void setAllConnections(const QList<ConnectionOption> &connections,
+ const QList<SingletonOption> &singeltons,
+ const QStringList &states);
+
+ void updateComboBoxes(int idx, ComboBox type);
+
+private:
+ void setupUIComponents();
+
+ void setType(ConnectionType type);
+
+ void fillAndSetTargetItem(const QString &value, bool useDefault = false);
+ void fillAndSetTargetProperty(const QString &value, bool useDefault = false);
+
+ void fillAndSetSourceItem(const QString &value, bool useDefault = false);
+ void fillAndSetSourceProperty(const QString &value,
+ QmlJS::AST::Node::Kind kind = QmlJS::AST::Node::Kind::Kind_Undefined,
+ bool useDefault = false);
+
+ void insertAndSetUndefined(QComboBox *comboBox);
+
+private:
+ QComboBox *m_comboBoxType = nullptr;
+
+ QStackedLayout *m_stackedLayout = nullptr;
+
+ QWidget *m_actionPlaceholder = nullptr;
+ QWidget *m_assignmentPlaceholder = nullptr;
+
+ QHBoxLayout *m_actionLayout = nullptr;
+ QHBoxLayout *m_assignmentLayout = nullptr;
+
+ QComboBox *m_actionTargetItem = nullptr;
+ QComboBox *m_actionMethod = nullptr;
+
+ QComboBox *m_assignmentTargetItem = nullptr;
+ QComboBox *m_assignmentTargetProperty = nullptr;
+ QComboBox *m_assignmentSourceItem = nullptr;
+ QComboBox *m_assignmentSourceProperty = nullptr; // Value
+
+ QList<ConnectionOption> m_connections;
+ QList<SingletonOption> m_singletons;
+ QStringList m_states;
+
+ const TypeName specificItem = {"specific"};
+ const TypeName singletonItem = {"singleton"};
+};
+
+}
+
+#endif //ACTIONEDITORDIALOG_H
diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp
index d2bdd3cbb8..5d7f8281d0 100644
--- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp
+++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp
@@ -28,6 +28,7 @@
#include <qmldesignerplugin.h>
#include <coreplugin/icore.h>
#include <coreplugin/actionmanager/actionmanager.h>
+#include <bindingeditor/bindingeditordialog.h>
#include <metainfo.h>
#include <qmlmodelnodeproxy.h>
@@ -60,14 +61,14 @@ void BindingEditor::prepareDialog()
{
if (s_lastBindingEditor)
s_lastBindingEditor->hideWidget();
+
s_lastBindingEditor = this;
m_dialog = new BindingEditorDialog(Core::ICore::dialogParent());
-
- QObject::connect(m_dialog, &BindingEditorDialog::accepted,
+ QObject::connect(m_dialog, &AbstractEditorDialog::accepted,
this, &BindingEditor::accepted);
- QObject::connect(m_dialog, &BindingEditorDialog::rejected,
+ QObject::connect(m_dialog, &AbstractEditorDialog::rejected,
this, &BindingEditor::rejected);
m_dialog->setAttribute(Qt::WA_DeleteOnClose);
@@ -89,8 +90,8 @@ void BindingEditor::hideWidget()
{
if (s_lastBindingEditor == this)
s_lastBindingEditor = nullptr;
- if (m_dialog)
- {
+
+ if (m_dialog) {
m_dialog->unregisterAutoCompletion(); //we have to do it separately, otherwise we have an autocompletion action override
m_dialog->close();
}
@@ -118,8 +119,7 @@ void BindingEditor::setBackendValue(const QVariant &backendValue)
const PropertyEditorValue *propertyEditorValue = qobject_cast<const PropertyEditorValue *>(backendValueObj);
const ModelNode node = propertyEditorValue->modelNode();
- if (node.isValid())
- {
+ if (node.isValid()) {
m_backendValueTypeName = node.metaInfo().propertyTypeName(propertyEditorValue->name());
if (m_backendValueTypeName == "alias" || m_backendValueTypeName == "unknown")
@@ -141,9 +141,8 @@ void BindingEditor::setModelNodeBackend(const QVariant &modelNodeBackend)
const auto backendObjectCasted =
qobject_cast<const QmlDesigner::QmlModelNodeProxy *>(modelNodeBackendObject);
- if (backendObjectCasted) {
+ if (backendObjectCasted)
m_modelNode = backendObjectCasted->qmlObjectNode().modelNode();
- }
emit modelNodeBackendChanged();
}
@@ -151,8 +150,7 @@ void BindingEditor::setModelNodeBackend(const QVariant &modelNodeBackend)
void BindingEditor::setStateModelNode(const QVariant &stateModelNode)
{
- if (stateModelNode.isValid())
- {
+ if (stateModelNode.isValid()) {
m_stateModelNode = stateModelNode;
m_modelNode = m_stateModelNode.value<QmlDesigner::ModelNode>();
@@ -188,21 +186,21 @@ void BindingEditor::prepareBindings()
const QList<TypeName> variantTypes = {"alias", "unknown", "variant", "var"};
const QList<TypeName> numericTypes = {"double", "real", "int"};
const QList<TypeName> colorTypes = {"QColor", "color"};
- auto isNumeric = [&numericTypes](TypeName compareType) { return numericTypes.contains(compareType); };
- auto isColor = [&colorTypes](TypeName compareType) { return colorTypes.contains(compareType); };
+ auto isVariant = [&variantTypes](const TypeName &compareType) { return variantTypes.contains(compareType); };
+ auto isNumeric = [&numericTypes](const TypeName &compareType) { return numericTypes.contains(compareType); };
+ auto isColor = [&colorTypes](const TypeName &compareType) { return colorTypes.contains(compareType); };
- const bool skipTypeFiltering = variantTypes.contains(m_backendValueTypeName);
+ const bool skipTypeFiltering = isVariant(m_backendValueTypeName);
const bool targetTypeIsNumeric = isNumeric(m_backendValueTypeName);
for (const auto &objnode : allNodes) {
BindingEditorDialog::BindingOption binding;
- for (const auto &propertyName : objnode.metaInfo().propertyNames())
- {
+ for (const auto &propertyName : objnode.metaInfo().propertyNames()) {
TypeName propertyTypeName = objnode.metaInfo().propertyTypeName(propertyName);
if (skipTypeFiltering
|| (m_backendValueTypeName == propertyTypeName)
- || variantTypes.contains(propertyTypeName)
+ || isVariant(propertyTypeName)
|| (targetTypeIsNumeric && isNumeric(propertyTypeName))) {
binding.properties.append(QString::fromUtf8(propertyName));
}
@@ -215,7 +213,7 @@ void BindingEditor::prepareBindings()
const TypeName dynamicTypeName = bindingProperty.dynamicTypeName();
if (skipTypeFiltering
|| (dynamicTypeName == m_backendValueTypeName)
- || variantTypes.contains(dynamicTypeName)
+ || isVariant(dynamicTypeName)
|| (targetTypeIsNumeric && isNumeric(dynamicTypeName))) {
binding.properties.append(QString::fromUtf8(bindingProperty.name()));
}
@@ -228,7 +226,7 @@ void BindingEditor::prepareBindings()
const TypeName dynamicTypeName = variantProperty.dynamicTypeName();
if (skipTypeFiltering
|| (dynamicTypeName == m_backendValueTypeName)
- || variantTypes.contains(dynamicTypeName)
+ || isVariant(dynamicTypeName)
|| (targetTypeIsNumeric && isNumeric(dynamicTypeName))) {
binding.properties.append(QString::fromUtf8(variantProperty.name()));
}
@@ -243,7 +241,7 @@ void BindingEditor::prepareBindings()
}
//singletons:
- if (RewriterView* rv = m_modelNode.view()->rewriterView()) {
+ if (RewriterView *rv = m_modelNode.view()->rewriterView()) {
for (const QmlTypeData &data : rv->getQMLTypes()) {
if (!data.typeName.isEmpty()) {
NodeMetaInfo metaInfo = m_modelNode.view()->model()->metaInfo(data.typeName.toUtf8());
@@ -256,7 +254,7 @@ void BindingEditor::prepareBindings()
if (skipTypeFiltering
|| (m_backendValueTypeName == propertyTypeName)
- || (variantTypes.contains(propertyTypeName))
+ || (isVariant(propertyTypeName))
|| (targetTypeIsNumeric && isNumeric(propertyTypeName))
|| (isColor(m_backendValueTypeName) && isColor(propertyTypeName))) {
binding.properties.append(QString::fromUtf8(propertyName));
@@ -281,9 +279,7 @@ void BindingEditor::prepareBindings()
void BindingEditor::updateWindowName()
{
if (!m_dialog.isNull() && !m_backendValueTypeName.isEmpty())
- {
m_dialog->setWindowTitle(m_dialog->defaultTitle() + " [" + m_backendValueTypeName + "]");
- }
}
QVariant BindingEditor::backendValue() const
diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.pri b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.pri
index 925cea3539..ff2920ffab 100644
--- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.pri
+++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.pri
@@ -1,9 +1,15 @@
HEADERS += $$PWD/bindingeditor.h
HEADERS += $$PWD/actioneditor.h
+HEADERS += $$PWD/abstracteditordialog.h
+HEADERS += $$PWD/actioneditordialog.h
HEADERS += $$PWD/bindingeditordialog.h
HEADERS += $$PWD/bindingeditorwidget.h
+HEADERS += $$PWD/connectionvisitor.h
SOURCES += $$PWD/bindingeditor.cpp
SOURCES += $$PWD/actioneditor.cpp
+SOURCES += $$PWD/abstracteditordialog.cpp
+SOURCES += $$PWD/actioneditordialog.cpp
SOURCES += $$PWD/bindingeditordialog.cpp
SOURCES += $$PWD/bindingeditorwidget.cpp
+SOURCES += $$PWD/connectionvisitor.cpp
diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.cpp
index 9d2b1cb9e0..b74d805f08 100644
--- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.cpp
+++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -41,80 +41,19 @@
namespace QmlDesigner {
-BindingEditorDialog::BindingEditorDialog(QWidget *parent, DialogType type)
- : QDialog(parent)
- , m_dialogType(type)
+BindingEditorDialog::BindingEditorDialog(QWidget *parent)
+ : AbstractEditorDialog(parent, tr("Binding Editor"))
{
- setWindowFlag(Qt::Tool, true);
- setWindowTitle(defaultTitle());
- 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);
-
- if (m_dialogType == DialogType::BindingDialog) {
- 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);
- }
+ QObject::connect(m_comboBoxItem, QOverload<int>::of(&QComboBox::currentIndexChanged),
+ this, &BindingEditorDialog::itemIDChanged);
+ QObject::connect(m_comboBoxProperty, QOverload<int>::of(&QComboBox::currentIndexChanged),
+ this, &BindingEditorDialog::propertyIDChanged);
}
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()
-{
- this->show();
- this->raise();
- m_editorWidget->setFocus();
-}
-
-void BindingEditorDialog::showWidget(int x, int y)
-{
- showWidget();
- move(QPoint(x, y));
-}
-
-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()
@@ -155,69 +94,26 @@ void BindingEditorDialog::adjustProperties()
m_comboBoxProperty->setCurrentText(property);
}
-void BindingEditorDialog::unregisterAutoCompletion()
+void BindingEditorDialog::setAllBindings(QList<BindingOption> bindings)
{
- if (m_editorWidget)
- m_editorWidget->unregisterAutoCompletion();
-}
-
-QString BindingEditorDialog::defaultTitle() const
-{
- return titleString;
-}
-
-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_lock = true;
+ m_bindings = bindings;
+ setupComboBoxes();
+ adjustProperties();
- 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);
+ m_lock = false;
}
void BindingEditorDialog::setupUIComponents()
{
- m_verticalLayout = new QVBoxLayout(this);
-
- if (m_dialogType == DialogType::BindingDialog) {
- 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_comboBoxItem = new QComboBox(this);
+ m_comboBoxProperty = new QComboBox(this);
- 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);
- if (m_dialogType == DialogType::BindingDialog) {
- 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);
+ //this->resize(660, 240);
}
void BindingEditorDialog::setupComboBoxes()
@@ -260,14 +156,4 @@ void BindingEditorDialog::propertyIDChanged(int propertyID)
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
index fdcdca0762..0c37abaa3a 100644
--- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.h
+++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -26,21 +26,15 @@
#ifndef BINDINGEDITORDIALOG_H
#define BINDINGEDITORDIALOG_H
-#include <bindingeditor/bindingeditorwidget.h>
-#include <texteditor/texteditor.h>
-
-#include <QDialog>
+#include <bindingeditor/abstracteditordialog.h>
QT_BEGIN_NAMESPACE
-class QDialogButtonBox;
-class QVBoxLayout;
-class QHBoxLayout;
class QComboBox;
QT_END_NAMESPACE
namespace QmlDesigner {
-class BindingEditorDialog : public QDialog
+class BindingEditorDialog : public AbstractEditorDialog
{
Q_OBJECT
@@ -57,52 +51,26 @@ public:
QStringList properties;
};
- enum DialogType {
- Unknown = 0,
- BindingDialog = 1,
- ActionDialog = 2
- };
-
-public:
- BindingEditorDialog(QWidget *parent = nullptr, DialogType type = DialogType::BindingDialog);
+ BindingEditorDialog(QWidget *parent = nullptr);
~BindingEditorDialog() override;
- void showWidget();
- void showWidget(int x, int y);
+ void adjustProperties() override;
- QString editorValue() const;
- void setEditorValue(const QString &text);
-
- void setAllBindings(QList<BindingEditorDialog::BindingOption> bindings);
- void adjustProperties();
-
- void unregisterAutoCompletion();
-
- QString defaultTitle() const;
+ void setAllBindings(QList<BindingOption> bindings);
private:
- void setupJSEditor();
void setupUIComponents();
void setupComboBoxes();
public slots:
void itemIDChanged(int);
void propertyIDChanged(int);
- void textChanged();
private:
- DialogType m_dialogType = DialogType::BindingDialog;
- 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]"};
- const QString titleString = {tr("Binding Editor")};
+
+ QList<BindingOption> m_bindings;
};
}
diff --git a/src/plugins/qmldesigner/components/bindingeditor/connectionvisitor.cpp b/src/plugins/qmldesigner/components/bindingeditor/connectionvisitor.cpp
new file mode 100644
index 0000000000..ddf328978f
--- /dev/null
+++ b/src/plugins/qmldesigner/components/bindingeditor/connectionvisitor.cpp
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 "connectionvisitor.h"
+
+namespace QmlDesigner {
+
+ConnectionVisitor::ConnectionVisitor()
+{
+}
+
+bool ConnectionVisitor::visit(QmlJS::AST::StringLiteral *ast)
+{
+ m_expression.append(qMakePair(QmlJS::AST::Node::Kind::Kind_StringLiteral,
+ ast->value.toString()));
+ return true;
+}
+
+bool ConnectionVisitor::visit(QmlJS::AST::NumericLiteral *ast)
+{
+ m_expression.append(qMakePair(QmlJS::AST::Node::Kind::Kind_NumericLiteral,
+ QString::number(ast->value)));
+ return true;
+}
+
+bool ConnectionVisitor::visit(QmlJS::AST::TrueLiteral *ast)
+{
+ Q_UNUSED(ast)
+ m_expression.append(qMakePair(QmlJS::AST::Node::Kind::Kind_TrueLiteral, QString("true")));
+ return true;
+}
+
+bool ConnectionVisitor::visit(QmlJS::AST::FalseLiteral *ast)
+{
+ Q_UNUSED(ast)
+ m_expression.append(qMakePair(QmlJS::AST::Node::Kind::Kind_FalseLiteral, QString("false")));
+ return true;
+}
+
+bool ConnectionVisitor::visit(QmlJS::AST::BinaryExpression *ast)
+{
+ Q_UNUSED(ast)
+ m_expression.append(qMakePair(QmlJS::AST::Node::Kind::Kind_BinaryExpression,
+ QString()));
+ return true;
+}
+
+bool ConnectionVisitor::visit(QmlJS::AST::CallExpression *ast)
+{
+ Q_UNUSED(ast)
+ m_expression.append(qMakePair(QmlJS::AST::Node::Kind::Kind_CallExpression,
+ QString()));
+ return true;
+}
+
+bool ConnectionVisitor::visit(QmlJS::AST::ArgumentList *ast)
+{
+ Q_UNUSED(ast)
+ m_expression.append(qMakePair(QmlJS::AST::Node::Kind::Kind_ArgumentList,
+ QString()));
+ return true;
+}
+
+bool ConnectionVisitor::visit(QmlJS::AST::FunctionExpression *ast)
+{
+ m_expression.append(qMakePair(QmlJS::AST::Node::Kind::Kind_FunctionExpression,
+ ast->name.toString()));
+ return true;
+}
+
+bool ConnectionVisitor::visit(QmlJS::AST::FieldMemberExpression *ast)
+{
+ m_expression.append(qMakePair(QmlJS::AST::Node::Kind::Kind_FieldMemberExpression,
+ ast->name.toString()));
+ return true;
+}
+
+bool ConnectionVisitor::visit(QmlJS::AST::IdentifierExpression *ast)
+{
+ m_expression.append(qMakePair(QmlJS::AST::Node::Kind::Kind_IdentifierExpression,
+ ast->name.toString()));
+ return true;
+}
+
+void ConnectionVisitor::throwRecursionDepthError()
+{
+ qWarning("Warning: Hit maximum recursion depth while visiting AST in ConnectionVisitor");
+}
+
+} // QmlDesigner namespace
diff --git a/src/plugins/qmldesigner/components/bindingeditor/connectionvisitor.h b/src/plugins/qmldesigner/components/bindingeditor/connectionvisitor.h
new file mode 100644
index 0000000000..abcebcdb8e
--- /dev/null
+++ b/src/plugins/qmldesigner/components/bindingeditor/connectionvisitor.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 CONNECTIONVISITOR_H
+#define CONNECTIONVISITOR_H
+
+#include <qmljs/qmljsdocument.h>
+#include <qmljs/parser/qmljsastvisitor_p.h>
+#include <qmljs/parser/qmljsast_p.h>
+
+namespace QmlDesigner {
+
+class ConnectionVisitor : public QmlJS::AST::Visitor
+{
+public:
+ explicit ConnectionVisitor();
+
+ bool visit(QmlJS::AST::StringLiteral *ast) override;
+ bool visit(QmlJS::AST::NumericLiteral *ast) override;
+ bool visit(QmlJS::AST::TrueLiteral *ast) override;
+ bool visit(QmlJS::AST::FalseLiteral *ast) override;
+
+ bool visit(QmlJS::AST::BinaryExpression *ast) override;
+ bool visit(QmlJS::AST::CallExpression *ast) override;
+
+ bool visit(QmlJS::AST::ArgumentList *ast) override;
+ bool visit(QmlJS::AST::FunctionExpression *ast) override; // unused
+
+ bool visit(QmlJS::AST::FieldMemberExpression *ast) override;
+ bool visit(QmlJS::AST::IdentifierExpression *ast) override;
+
+ void throwRecursionDepthError() override;
+
+ const QList<QPair<QmlJS::AST::Node::Kind, QString>> &expression() const {
+ return m_expression;
+ }
+
+private:
+ QList<QPair<QmlJS::AST::Node::Kind, QString>> m_expression;
+};
+
+}
+
+#endif //CONNECTIONVISITOR_H
diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
index 89151b7ea6..254d43f4fd 100644
--- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
@@ -26,14 +26,15 @@
#include "designeractionmanager.h"
#include "changestyleaction.h"
+#include "designeractionmanagerview.h"
#include "modelnodecontextmenu_helper.h"
+#include "qmldesignerconstants.h"
+#include "rewritingexception.h"
#include <bindingproperty.h>
-#include <nodeproperty.h>
-#include <nodelistproperty.h>
#include <nodehints.h>
+#include <nodelistproperty.h>
#include <nodemetainfo.h>
-#include "designeractionmanagerview.h"
-#include "qmldesignerconstants.h"
+#include <nodeproperty.h>
#include <formeditortoolbutton.h>
@@ -44,8 +45,6 @@
#include <listmodeleditor/listmodeleditordialog.h>
#include <listmodeleditor/listmodeleditormodel.h>
-#include <QHBoxLayout>
-#include <QGraphicsLinearLayout>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/icore.h>
@@ -53,6 +52,12 @@
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
+#include <QGraphicsLinearLayout>
+#include <QHBoxLayout>
+#include <QMessageBox>
+
+#include <exception>
+
namespace QmlDesigner {
static inline QString captionForModelNode(const ModelNode &modelNode)
@@ -387,6 +392,12 @@ public:
}
};
+class DocumentError : public std::exception
+{
+public:
+ const char *what() const noexcept override { return "Current document contains errors."; }
+};
+
class EditListModelAction final : public ModelNodeContextMenuAction
{
public:
@@ -432,6 +443,24 @@ public:
return view->createModelNode(elementMetaInfo.typeName(),
elementMetaInfo.majorVersion(),
elementMetaInfo.minorVersion());
+ },
+ [&](const ModelNode &node) {
+ bool isNowInComponent = ModelNodeOperations::goIntoComponent(
+ node);
+
+ Model *currentModel = QmlDesignerPlugin::instance()
+ ->currentDesignDocument()
+ ->currentModel();
+
+ if (currentModel->rewriterView()
+ && currentModel->rewriterView()->inErrorState()) {
+ throw DocumentError{};
+ }
+
+ if (isNowInComponent)
+ return view->rootModelNode();
+
+ return node;
}};
model.setListView(targetNode);
@@ -439,7 +468,22 @@ public:
ListModelEditorDialog dialog{Core::ICore::mainWindow()};
dialog.setModel(&model);
- dialog.exec();
+ try {
+ dialog.exec();
+ } catch (const DocumentError &) {
+ QMessageBox::warning(
+ Core::ICore::mainWindow(),
+ QCoreApplication::translate("DesignerActionManager", "Document has errors"),
+ QCoreApplication::translate("DesignerActionManager",
+ "The document which contains the list model "
+ "contains errors. So we cannot edit it."));
+ } catch (const RewritingException &) {
+ QMessageBox::warning(
+ Core::ICore::mainWindow(),
+ QCoreApplication::translate("DesignerActionManager", "Document cannot be written"),
+ QCoreApplication::translate("DesignerActionManager",
+ "An error occurred during a write attemp."));
+ }
}
};
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
index a78ac045ac..cf22a9bbcf 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
@@ -127,9 +127,9 @@ static void setUpperLeftPostionToNode(const ModelNode &layoutNode, const QList<M
namespace ModelNodeOperations {
-void goIntoComponent(const ModelNode &modelNode)
+bool goIntoComponent(const ModelNode &modelNode)
{
- DocumentManager::goIntoComponent(modelNode);
+ return DocumentManager::goIntoComponent(modelNode);
}
void select(const SelectionContext &selectionState)
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h
index 9e7d53651a..a829545748 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h
@@ -30,7 +30,7 @@
namespace QmlDesigner {
namespace ModelNodeOperations {
-void goIntoComponent(const ModelNode &modelNode);
+bool goIntoComponent(const ModelNode &modelNode);
void select(const SelectionContext &selectionState);
void deSelect(const SelectionContext &selectionState);
diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp
index 25ea5814a9..c650be4221 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp
+++ b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp
@@ -60,7 +60,7 @@ ConnectionViewWidget::ConnectionViewWidget(QWidget *parent) :
QFrame(parent),
ui(new Ui::ConnectionViewWidget)
{
- m_connectonEditor = new QmlDesigner::ActionEditor(this);
+ m_connectionEditor = new QmlDesigner::ActionEditor(this);
m_bindingEditor = new QmlDesigner::BindingEditor(this);
m_dynamicEditor = new QmlDesigner::BindingEditor(this);
@@ -111,7 +111,7 @@ ConnectionViewWidget::ConnectionViewWidget(QWidget *parent) :
ConnectionViewWidget::~ConnectionViewWidget()
{
- delete m_connectonEditor;
+ delete m_connectionEditor;
delete m_bindingEditor;
delete m_dynamicEditor;
delete ui;
@@ -161,10 +161,14 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event)
menu.addAction(tr("Open Connection Editor"), [&]() {
if (index.isValid()) {
- m_connectonEditor->showWidget();
- m_connectonEditor->setBindingValue(index.data().toString());
- m_connectonEditor->setModelIndex(index);
- m_connectonEditor->updateWindowName();
+ auto *connectionModel = qobject_cast<ConnectionModel *>(targetView->model());
+ ModelNode node = connectionModel->connectionView()->rootModelNode();
+ m_connectionEditor->showWidget();
+ m_connectionEditor->setConnectionValue(index.data().toString());
+ m_connectionEditor->setModelIndex(index);
+ m_connectionEditor->setModelNode(node);
+ m_connectionEditor->prepareConnections();
+ m_connectionEditor->updateWindowName();
}
});
@@ -455,29 +459,29 @@ void ConnectionViewWidget::addButtonClicked()
void ConnectionViewWidget::editorForConnection()
{
- QObject::connect(m_connectonEditor, &QmlDesigner::ActionEditor::accepted,
+ QObject::connect(m_connectionEditor, &QmlDesigner::ActionEditor::accepted,
[&]() {
- if (m_connectonEditor->hasModelIndex()) {
+ if (m_connectionEditor->hasModelIndex()) {
ConnectionModel *connectionModel = qobject_cast<ConnectionModel *>(ui->connectionView->model());
if (connectionModel->connectionView()->isWidgetEnabled()
- && (connectionModel->rowCount() > m_connectonEditor->modelIndex().row())) {
+ && (connectionModel->rowCount() > m_connectionEditor->modelIndex().row())) {
connectionModel->connectionView()
->executeInTransaction("ConnectionView::setSignal", [this, connectionModel]() {
SignalHandlerProperty signalHandler
= connectionModel->signalHandlerPropertyForRow(
- m_connectonEditor->modelIndex().row());
- signalHandler.setSource(m_connectonEditor->bindingValue());
+ m_connectionEditor->modelIndex().row());
+ signalHandler.setSource(m_connectionEditor->connectionValue());
});
}
- m_connectonEditor->resetModelIndex();
+ m_connectionEditor->resetModelIndex();
}
- m_connectonEditor->hideWidget();
+ m_connectionEditor->hideWidget();
});
- QObject::connect(m_connectonEditor, &QmlDesigner::ActionEditor::rejected,
+ QObject::connect(m_connectionEditor, &QmlDesigner::ActionEditor::rejected,
[&]() {
- m_connectonEditor->resetModelIndex();
- m_connectonEditor->hideWidget();
+ m_connectionEditor->resetModelIndex();
+ m_connectionEditor->hideWidget();
});
}
diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.h b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.h
index 68319e16b5..dc12d53564 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.h
+++ b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.h
@@ -107,7 +107,7 @@ private:
private:
Ui::ConnectionViewWidget *ui;
- QmlDesigner::ActionEditor *m_connectonEditor; //editor for connections in connection view
+ QmlDesigner::ActionEditor *m_connectionEditor; //editor for connections in connection view
QmlDesigner::BindingEditor *m_bindingEditor; //editor for properties in binding view
QmlDesigner::BindingEditor *m_dynamicEditor; //editor for properties in dynamic view
diff --git a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp
index 62b8b78088..e6e10a017c 100644
--- a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp
+++ b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp
@@ -199,13 +199,15 @@ void renameProperties(const QStandardItemModel *model,
}
ModelNode listModelNode(const ModelNode &listViewNode,
- const std::function<ModelNode()> &createModelCallback)
+ const std::function<ModelNode()> &createModelCallback,
+ const std::function<ModelNode(const ModelNode &)> &goIntoComponentCallback)
{
if (listViewNode.hasProperty("model")) {
- if (listViewNode.hasBindingProperty("model"))
- return listViewNode.bindingProperty("model").resolveToModelNode();
- else if (listViewNode.hasNodeProperty("model"))
- return listViewNode.nodeProperty("model").modelNode();
+ if (listViewNode.hasBindingProperty("model")) {
+ return goIntoComponentCallback(listViewNode.bindingProperty("model").resolveToModelNode());
+ } else if (listViewNode.hasNodeProperty("model")) {
+ return goIntoComponentCallback(listViewNode.nodeProperty("model").modelNode());
+ }
}
ModelNode newModel = createModelCallback();
@@ -251,7 +253,7 @@ void ListModelEditorModel::setListModel(ModelNode node)
void ListModelEditorModel::setListView(ModelNode listView)
{
- setListModel(listModelNode(listView, m_createModelCallback));
+ setListModel(listModelNode(listView, m_createModelCallback, m_goIntoComponentCallback));
}
void ListModelEditorModel::addRow()
diff --git a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.h b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.h
index 97bd9c18d8..5d3b87bbd7 100644
--- a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.h
+++ b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.h
@@ -39,9 +39,11 @@ class ListModelEditorModel : public QStandardItemModel
public:
ListModelEditorModel(std::function<ModelNode()> createModelCallback,
- std::function<ModelNode()> createElementCallback)
+ std::function<ModelNode()> createElementCallback,
+ std::function<ModelNode(const ModelNode &)> goIntoComponentCallback)
: m_createModelCallback(std::move(createModelCallback))
, m_createElementCallback(std::move(createElementCallback))
+ , m_goIntoComponentCallback(std::move(goIntoComponentCallback))
{}
void setListModel(ModelNode node);
@@ -76,6 +78,7 @@ private:
QList<QmlDesigner::PropertyName> m_propertyNames;
std::function<ModelNode()> m_createModelCallback;
std::function<ModelNode()> m_createElementCallback;
+ std::function<ModelNode(const ModelNode &)> m_goIntoComponentCallback;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/documentmanager.cpp b/src/plugins/qmldesigner/documentmanager.cpp
index 4550d8a4ea..109b6577b4 100644
--- a/src/plugins/qmldesigner/documentmanager.cpp
+++ b/src/plugins/qmldesigner/documentmanager.cpp
@@ -271,7 +271,7 @@ void DocumentManager::removeEditors(const QList<Core::IEditor *> &editors)
delete m_designDocumentHash.take(editor).data();
}
-void DocumentManager::goIntoComponent(const ModelNode &modelNode)
+bool DocumentManager::goIntoComponent(const ModelNode &modelNode)
{
if (modelNode.isValid() && modelNode.isComponent() && designDocument()) {
QmlDesignerPlugin::instance()->viewManager().setComponentNode(modelNode);
@@ -286,9 +286,14 @@ void DocumentManager::goIntoComponent(const ModelNode &modelNode)
openComponentSourcePropertyOfLoader(modelNode);
else
openInlineComponent(modelNode);
+
ModelNode rootModelNode = designDocument()->rewriterView()->rootModelNode();
applyProperties(rootModelNode, oldProperties);
+
+ return true;
}
+
+ return false;
}
bool DocumentManager::createFile(const QString &filePath, const QString &contents)
diff --git a/src/plugins/qmldesigner/documentmanager.h b/src/plugins/qmldesigner/documentmanager.h
index bb3b13c9ac..8cd67eca9f 100644
--- a/src/plugins/qmldesigner/documentmanager.h
+++ b/src/plugins/qmldesigner/documentmanager.h
@@ -51,7 +51,7 @@ public:
void removeEditors(const QList<Core::IEditor *> &editors);
- static void goIntoComponent(const ModelNode &modelNode);
+ static bool goIntoComponent(const ModelNode &modelNode);
static bool createFile(const QString &filePath, const QString &contents);
static void addFileToVersionControl(const QString &directoryPath, const QString &newFilePath);
diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs
index 5c7ec4efc6..f95f853c7d 100644
--- a/src/plugins/qmldesigner/qmldesignerplugin.qbs
+++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs
@@ -698,10 +698,16 @@ Project {
"bindingeditor/bindingeditor.h",
"bindingeditor/actioneditor.cpp",
"bindingeditor/actioneditor.h",
+ "bindingeditor/abstracteditordialog.cpp",
+ "bindingeditor/abstracteditordialog.h",
+ "bindingeditor/actioneditordialog.cpp",
+ "bindingeditor/actioneditordialog.h",
"bindingeditor/bindingeditordialog.cpp",
"bindingeditor/bindingeditordialog.h",
"bindingeditor/bindingeditorwidget.cpp",
"bindingeditor/bindingeditorwidget.h",
+ "bindingeditor/connectionvisitor.cpp",
+ "bindingeditor/connectionvisitor.h",
"colortool/colortool.cpp",
"colortool/colortool.h",
"connectioneditor/addnewbackenddialog.h",
diff --git a/src/plugins/texteditor/textmark.cpp b/src/plugins/texteditor/textmark.cpp
index 47e5f54f76..dff6b86d63 100644
--- a/src/plugins/texteditor/textmark.cpp
+++ b/src/plugins/texteditor/textmark.cpp
@@ -24,6 +24,8 @@
****************************************************************************/
#include "textmark.h"
+
+#include "fontsettings.h"
#include "textdocument.h"
#include "texteditor.h"
#include "texteditorplugin.h"
@@ -139,8 +141,10 @@ void TextMark::paintAnnotation(QPainter &painter, QRectF *annotationRect,
const QColor &markColor = m_color.has_value()
? Utils::creatorTheme()->color(m_color.value()).toHsl()
: painter.pen().color();
+
+ const FontSettings &fontSettings = m_baseTextDocument->fontSettings();
const AnnotationColors &colors = AnnotationColors::getAnnotationColors(
- markColor, painter.background().color());
+ markColor, fontSettings.toTextCharFormat(C_TEXT).background().color());
painter.save();
QLinearGradient grad(rects.fadeInRect.topLeft() - contentOffset,
diff --git a/src/tools/clangbackend/source/tokeninfo.cpp b/src/tools/clangbackend/source/tokeninfo.cpp
index de40a954e1..47b8188986 100644
--- a/src/tools/clangbackend/source/tokeninfo.cpp
+++ b/src/tools/clangbackend/source/tokeninfo.cpp
@@ -317,6 +317,7 @@ void TokenInfo::typeKind(const Cursor &cursor)
m_types.mixinHighlightingTypes.push_back(HighlightingType::Namespace);
return;
case CXCursor_TypeAliasDecl:
+ case CXCursor_TypeAliasTemplateDecl:
m_types.mixinHighlightingTypes.push_back(HighlightingType::TypeAlias);
return;
case CXCursor_TypedefDecl: