From f7808af946d13d97731ada3b1e3e6e73143a233c Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 16 Oct 2019 15:42:28 +0200 Subject: [PATCH 01/57] Update qbs submodule To HEAD of 1.14 branch. Change-Id: I3106078a808ddddc0211d46e871c66383746aec3 Reviewed-by: Joerg Bornemann --- src/shared/qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/qbs b/src/shared/qbs index aec975a3f95..665db9c9dd9 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit aec975a3f95f905b2d63ea1500ace28eddea7b9e +Subproject commit 665db9c9dd9ced277eebe7dce0f908dc2cb0825b From 418c7d108ac2324d1a10c7f769618eecae01f399 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 14 Oct 2019 09:54:28 +0200 Subject: [PATCH 02/57] AutoTest: Fix handling of parameterized boost tests Setting the parameterized flag after the test case may have been added to the found tests is useless. Do it as early as possible to take it into account when gathering information for location and type. Beside this the filter for parameterized boost tests had been wrong which in turn led to not executing them at all. Change-Id: I1a4345b2a751c79cc4fc6df8e201e9606c961aaf Reviewed-by: David Schulz --- src/plugins/autotest/boost/boostcodeparser.cpp | 3 +-- src/plugins/autotest/boost/boosttesttreeitem.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/plugins/autotest/boost/boostcodeparser.cpp b/src/plugins/autotest/boost/boostcodeparser.cpp index 79c612285b1..526bbf13889 100644 --- a/src/plugins/autotest/boost/boostcodeparser.cpp +++ b/src/plugins/autotest/boost/boostcodeparser.cpp @@ -105,6 +105,7 @@ void BoostCodeParser::handleIdentifier() } else if (identifier == "BOOST_TEST_CASE") { handleTestCase(TestCaseType::Functions); } else if (identifier == "BOOST_PARAM_TEST_CASE") { + m_currentState.setFlag(BoostTestTreeItem::Parameterized); handleTestCase(TestCaseType::Parameter); } else if (identifier == "BOOST_AUTO_TEST_CASE") { handleTestCase(TestCaseType::Auto); @@ -203,8 +204,6 @@ void BoostCodeParser::handleTestCase(TestCaseType testCaseType) m_currentState = BoostTestTreeItem::Enabled; return; } - if (testCaseType == TestCaseType::Parameter) - m_currentState |= BoostTestTreeItem::Parameterized; } else if (m_currentState.testFlag(BoostTestTreeItem::Fixture)) { // ignore first parameter (fixture) and first comma if (!skipCommentsUntil(T_IDENTIFIER)) diff --git a/src/plugins/autotest/boost/boosttesttreeitem.cpp b/src/plugins/autotest/boost/boosttesttreeitem.cpp index e2e58c28aff..556546f6a44 100644 --- a/src/plugins/autotest/boost/boosttesttreeitem.cpp +++ b/src/plugins/autotest/boost/boosttesttreeitem.cpp @@ -236,6 +236,8 @@ QList BoostTestTreeItem::getSelectedTestConfigurations() co QString tcName = item->name(); if (item->state().testFlag(BoostTestTreeItem::Templated)) tcName.append("<*"); + else if (item->state().testFlag(BoostTestTreeItem::Parameterized)) + tcName.append('*'); tcName = handleSpecialFunctionNames(tcName); testCasesForProjectFile[item->proFile()].testCases.append( item->prependWithParentsSuitePaths(tcName)); @@ -271,6 +273,8 @@ TestConfiguration *BoostTestTreeItem::testConfiguration() const QString tcName = handleSpecialFunctionNames(boostItem->name()); if (boostItem->type() == TestSuite) // execute everything below a suite tcName.append("/*"); + else if (boostItem->state().testFlag(BoostTestTreeItem::Parameterized)) + tcName.append('*'); else if (boostItem->state().testFlag(BoostTestTreeItem::Templated)) tcName.append("<*"); testCases.append(boostItem->prependWithParentsSuitePaths(tcName)); @@ -281,6 +285,8 @@ TestConfiguration *BoostTestTreeItem::testConfiguration() const QString tcName = name(); if (state().testFlag(BoostTestTreeItem::Templated)) tcName.append("<*"); + else if (state().testFlag(BoostTestTreeItem::Parameterized)) + tcName.append('*'); testCases.append(prependWithParentsSuitePaths(handleSpecialFunctionNames(tcName))); } From cc1399a4b672aa4b9679b1febff3c8c762842612 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 17 Oct 2019 14:10:32 +0200 Subject: [PATCH 03/57] Debugger: Fix crash after breakpoint marker drag&drop The updateMarker function deletes the marker of the global breakpoint so don't call that function from the marker. Fixes: QTCREATORBUG-23107 Change-Id: I377608f1a08b61451be1fc0be5bc15252252a4a7 Reviewed-by: hjk --- src/plugins/debugger/breakhandler.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index 8befb49f8e0..4beee1d5a64 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -170,7 +170,6 @@ public: // the next line that generated code. m_gbp->m_params.lineNumber = lineNumber; - m_gbp->updateMarker(); m_gbp->update(); } @@ -186,14 +185,11 @@ public: void dragToLine(int line) final { + TextMark::move(line); QTC_ASSERT(m_gbp, return); QTC_ASSERT(BreakpointManager::globalBreakpoints().contains(m_gbp), return); - BreakpointParameters params = m_gbp->m_params; - params.lineNumber = line; - GlobalBreakpoint gbp = m_gbp; - m_gbp = GlobalBreakpoint(); - gbp->deleteBreakpoint(); - m_gbp = BreakpointManager::createBreakpoint(params); + m_gbp->m_params.lineNumber = line; + m_gbp->update(); } bool isClickable() const final { return true; } From fa8ff4108f646e6f3d9a3b8d4b59abd1a299ae10 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 17 Oct 2019 14:35:25 +0200 Subject: [PATCH 04/57] Debugger: further untangle of breakpoint item and marker Change-Id: I9331912c1b53a0110479f46ef1e576676441ab75 Reviewed-by: hjk --- src/plugins/debugger/breakhandler.cpp | 21 +++++++++++++++------ src/plugins/debugger/breakhandler.h | 1 - 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index 4beee1d5a64..22fd4a4008d 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -169,16 +169,14 @@ public: // running, as this can be triggered by moving the breakpoint to // the next line that generated code. - m_gbp->m_params.lineNumber = lineNumber; - m_gbp->update(); + m_gbp->updateLineNumber(lineNumber); } void updateFileName(const FilePath &fileName) final { TextMark::updateFileName(fileName); QTC_ASSERT(m_gbp, return); - m_gbp->m_params.fileName = fileName.toString(); - m_gbp->update(); + m_gbp->updateFileName(fileName); } bool isDraggable() const final { return true; } @@ -188,8 +186,7 @@ public: TextMark::move(line); QTC_ASSERT(m_gbp, return); QTC_ASSERT(BreakpointManager::globalBreakpoints().contains(m_gbp), return); - m_gbp->m_params.lineNumber = line; - m_gbp->update(); + m_gbp->updateLineNumber(line); } bool isClickable() const final { return true; } @@ -2261,6 +2258,18 @@ void GlobalBreakpointItem::removeBreakpointFromModel() theBreakpointManager->destroyItem(this); } +void GlobalBreakpointItem::updateLineNumber(int lineNumber) +{ + m_params.lineNumber = lineNumber; + update(); +} + +void GlobalBreakpointItem::updateFileName(const FilePath &fileName) +{ + m_params.fileName = fileName.toString(); + update(); +} + QString GlobalBreakpointItem::markerFileName() const { // Some heuristics to find a "good" file name. diff --git a/src/plugins/debugger/breakhandler.h b/src/plugins/debugger/breakhandler.h index 83d934034b6..fa7434657f3 100644 --- a/src/plugins/debugger/breakhandler.h +++ b/src/plugins/debugger/breakhandler.h @@ -93,7 +93,6 @@ private: friend class BreakHandler; friend class BreakpointManager; friend class BreakpointMarker; - friend class GlobalBreakpointMarker; void updateMarker(); void updateMarkerIcon(); From b9b2d5ef5d3366b67aef797a4c07d508ddb034b0 Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Tue, 1 Oct 2019 10:32:53 +0200 Subject: [PATCH 05/57] Remove extra setMargin(..) Some lines after we can see a setContentsMargins Change-Id: I376129566c7df466a3413f001b42c670ee7c7022 Reviewed-by: hjk --- src/libs/qmleditorwidgets/contextpanewidget.cpp | 1 - src/libs/qmleditorwidgets/contextpanewidgetimage.cpp | 1 - src/libs/utils/fancymainwindow.cpp | 1 - src/plugins/bineditor/bineditorplugin.cpp | 1 - src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp | 1 - 5 files changed, 5 deletions(-) diff --git a/src/libs/qmleditorwidgets/contextpanewidget.cpp b/src/libs/qmleditorwidgets/contextpanewidget.cpp index d09902be1b5..d628ae5eed2 100644 --- a/src/libs/qmleditorwidgets/contextpanewidget.cpp +++ b/src/libs/qmleditorwidgets/contextpanewidget.cpp @@ -158,7 +158,6 @@ void DragWidget::enterEvent(QEvent *) ContextPaneWidget::ContextPaneWidget(QWidget *parent) : DragWidget(parent), m_currentWidget(0) { QGridLayout *layout = new QGridLayout(this); - layout->setMargin(0); layout->setContentsMargins(1, 1, 1, 1); layout->setSpacing(0); m_toolButton = new QToolButton(this); diff --git a/src/libs/qmleditorwidgets/contextpanewidgetimage.cpp b/src/libs/qmleditorwidgets/contextpanewidgetimage.cpp index dcc3e9ecc66..abe974ee5c4 100644 --- a/src/libs/qmleditorwidgets/contextpanewidgetimage.cpp +++ b/src/libs/qmleditorwidgets/contextpanewidgetimage.cpp @@ -884,7 +884,6 @@ PreviewDialog::PreviewDialog(QWidget *parent) : DragWidget(parent) QVBoxLayout *layout = new QVBoxLayout(this); QHBoxLayout *horizontalLayout = new QHBoxLayout(); QHBoxLayout *horizontalLayout2 = new QHBoxLayout(); - layout->setMargin(0); layout->setContentsMargins(2, 2, 2, 16); layout->setSpacing(4); QToolButton *toolButton = new QToolButton(this); diff --git a/src/libs/utils/fancymainwindow.cpp b/src/libs/utils/fancymainwindow.cpp index 9a5c84894c3..5398218789c 100644 --- a/src/libs/utils/fancymainwindow.cpp +++ b/src/libs/utils/fancymainwindow.cpp @@ -182,7 +182,6 @@ public: m_maximumActiveSize = QSize(maxWidth, activeHeight); auto layout = new QHBoxLayout(this); - layout->setMargin(0); layout->setSpacing(0); layout->setContentsMargins(4, 0, 0, 0); layout->addWidget(m_titleLabel); diff --git a/src/plugins/bineditor/bineditorplugin.cpp b/src/plugins/bineditor/bineditorplugin.cpp index 9fbba5c7f85..b6bc79d23ad 100644 --- a/src/plugins/bineditor/bineditorplugin.cpp +++ b/src/plugins/bineditor/bineditorplugin.cpp @@ -368,7 +368,6 @@ public: auto l = new QHBoxLayout; auto w = new QWidget; - l->setMargin(0); l->setContentsMargins(0, 0, 5, 0); l->addStretch(1); l->addWidget(m_addressEdit); diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp index 8fd25083154..627299c64e7 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp @@ -637,7 +637,6 @@ ClangEditorDocumentProcessor::creatorForHeaderErrorDiagnosticWidget( return [firstHeaderErrorDiagnostic]() { auto vbox = new QVBoxLayout; - vbox->setMargin(0); vbox->setContentsMargins(10, 0, 0, 2); vbox->setSpacing(2); From 383ea95889d7f841ebe5047572861febf65f0450 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 17 Oct 2019 14:46:26 +0200 Subject: [PATCH 06/57] Debugger: Avoid recreation of breakpoint markers Change-Id: Ie3b160a7b7137257b2028d03878700675142102f Reviewed-by: hjk --- src/plugins/debugger/breakhandler.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index 22fd4a4008d..63b03189bed 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -2260,13 +2260,18 @@ void GlobalBreakpointItem::removeBreakpointFromModel() void GlobalBreakpointItem::updateLineNumber(int lineNumber) { + if (m_params.lineNumber == lineNumber) + return; m_params.lineNumber = lineNumber; update(); } void GlobalBreakpointItem::updateFileName(const FilePath &fileName) { - m_params.fileName = fileName.toString(); + const QString &file = fileName.toString(); + if (m_params.fileName == file) + return; + m_params.fileName = file; update(); } @@ -2305,11 +2310,14 @@ void GlobalBreakpointItem::updateMarker() const FilePath file = FilePath::fromString(m_params.fileName); const int line = m_params.lineNumber; - if (m_marker && (file != m_marker->fileName() || line != m_marker->lineNumber())) - destroyMarker(); - - if (!m_marker && !file.isEmpty() && line > 0) + if (m_marker) { + if (file != m_marker->fileName()) + m_marker->updateFileName(file); + if (line != m_marker->lineNumber()) + m_marker->move(line); + } else if (!file.isEmpty() && line > 0) { m_marker = new GlobalBreakpointMarker(this, file, line); + } if (m_marker) m_marker->setToolTip(toolTip()); From 8c7dd57645ab30f760846f7cbf57121d763d8473 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Wed, 2 Oct 2019 09:28:43 +0200 Subject: [PATCH 07/57] Clang: Build against LLVM/Clang 9 Task-numer: QTCREATORBUG-23038 Change-Id: I3608bca6541614bb55e67d35c87334957cd02761 Reviewed-by: Cristian Adam Reviewed-by: Konstantin Tokarev (cherry picked from commit 6ec8017bc675692f3d325c0cd95c9c4c7a79db7d) Reviewed-by: Orgad Shaneh --- src/plugins/clangformat/clangformatutils.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index 59c2b592d78..f087f77a948 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -60,7 +60,11 @@ static clang::format::FormatStyle qtcStyle() style.AllowShortBlocksOnASingleLine = false; style.AllowShortCaseLabelsOnASingleLine = false; style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; +#if LLVM_VERSION_MAJOR >= 9 + style.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never; +#else style.AllowShortIfStatementsOnASingleLine = false; +#endif style.AllowShortLoopsOnASingleLine = false; style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; style.AlwaysBreakBeforeMultilineStrings = false; From 708179285de9f58e8578b72f7320c37b6252c45f Mon Sep 17 00:00:00 2001 From: Alexis Murzeau Date: Mon, 14 Oct 2019 23:52:16 +0200 Subject: [PATCH 08/57] MsvcToolchain: Fix "detection" of supported ABIs for msvc2010 Always ensure that supportedAbis includes targetAbi so toolchains that don't have any vcvars32.bat or the like (like msvc2010) are restored correctly at startup. The cache-miss case is just shifted inside a else clause so the added code is executed both in case of cache hit or miss. The targetAbi is added to m_supportedAbis but is not cached in abiCache as the abiCache has only vcVarsBat as the key, which is the same for all toolchains of the same compiler but different architecture. This way, even if the common supportedAbis is retrieved from the cache, the presence of targetAbi is always checked and added if needed. With this modification to detectInstalledAbis(), setSupportedAbi is not needed anymore as it is redundant. Now msvc2015 build tools case is handled the same way as msvc2010 in detectInstalledAbis(). This effectively reverts 2896e5f5e289a30928ab679c99d7de68d4a903ac. Also, the existing QTC_ASSERT(m_supportedAbis.isEmpty(), return); in detectInstalledAbis() is removed as when vcVars is changed, it can have a new uncached vcVarsBase while having supportedAbis set already (via a call to changeVcVarsCall). This happens for clang-cl toolchains that inherit MsvcToolchain but change vcVarsBat in ClangClToolChain::resetMsvcToolChain later (in ClangClToolChain::detectClangClToolChainInPath). Task-number: QTCREATORBUG-22960 Change-Id: Iaad5ea1dc649393037a3d32faa9075153974b5cb Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/msvctoolchain.cpp | 72 ++++++++++--------- src/plugins/projectexplorer/msvctoolchain.h | 2 - 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index 17bf393a4c1..39f9d8ea8a0 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -776,39 +776,51 @@ void MsvcToolChain::updateEnvironmentModifications(QList void MsvcToolChain::detectInstalledAbis() { - if (!m_supportedAbis.isEmpty()) // Build Tools 2015 - return; static QMap abiCache; const QString vcVarsBase = QDir::fromNativeSeparators(m_vcvarsBat).left(m_vcvarsBat.lastIndexOf('/')); if (abiCache.contains(vcVarsBase)) { m_supportedAbis = abiCache.value(vcVarsBase); - return; + } else { + // Clear previously detected m_supportedAbis to repopulate it. + m_supportedAbis.clear(); + const Abi baseAbi = targetAbi(); + for (MsvcPlatform platform : platforms) { + bool toolchainInstalled = false; + QString perhapsVcVarsPath = vcVarsBase + QLatin1Char('/') + QLatin1String(platform.bat); + const Platform p = platform.platform; + if (QFileInfo(perhapsVcVarsPath).isFile()) { + toolchainInstalled = true; + } else { + // MSVC 2015 and below had various versions of vcvars scripts in subfolders. Try these + // as fallbacks. + perhapsVcVarsPath = vcVarsBase + platform.prefix + QLatin1Char('/') + + QLatin1String(platform.bat); + toolchainInstalled = QFileInfo(perhapsVcVarsPath).isFile(); + } + if (hostSupportsPlatform(platform.platform) && toolchainInstalled) { + Abi newAbi(archForPlatform(p), + baseAbi.os(), + baseAbi.osFlavor(), + baseAbi.binaryFormat(), + wordWidthForPlatform(p)); + if (!m_supportedAbis.contains(newAbi)) + m_supportedAbis.append(newAbi); + } + } + + abiCache.insert(vcVarsBase, m_supportedAbis); } - QTC_ASSERT(m_supportedAbis.isEmpty(), return); - const Abi baseAbi = targetAbi(); - for (MsvcPlatform platform : platforms) { - bool toolchainInstalled = false; - QString perhapsVcVarsPath = vcVarsBase + QLatin1Char('/') + QLatin1String(platform.bat); - const Platform p = platform.platform; - if (QFileInfo(perhapsVcVarsPath).isFile()) { - toolchainInstalled = true; - } else { - // MSVC 2015 and below had various versions of vcvars scripts in subfolders. Try these - // as fallbacks. - perhapsVcVarsPath = vcVarsBase + platform.prefix + QLatin1Char('/') - + QLatin1String(platform.bat); - toolchainInstalled = QFileInfo(perhapsVcVarsPath).isFile(); - } - if (hostSupportsPlatform(platform.platform) && toolchainInstalled) { - Abi newAbi(archForPlatform(p), baseAbi.os(), baseAbi.osFlavor(), baseAbi.binaryFormat(), - wordWidthForPlatform(p)); - if (!m_supportedAbis.contains(newAbi)) - m_supportedAbis.append(newAbi); - } - } - abiCache.insert(vcVarsBase, m_supportedAbis); + // Always add targetAbi in supportedAbis if it is empty. + // targetAbi is the abi with which the toolchain was detected. + // This is necessary for toolchains that don't have vcvars32.bat and the like in their + // vcVarsBase path, like msvc2010. + // Also, don't include that one in abiCache to avoid polluting it with values specific + // to one toolchain as the cache is global for a vcVarsBase path. For this reason, the + // targetAbi needs to be added manually. + if (m_supportedAbis.empty()) + m_supportedAbis.append(targetAbi()); } Utils::Environment MsvcToolChain::readEnvironmentSetting(const Utils::Environment &env) const @@ -1284,13 +1296,6 @@ void MsvcToolChain::changeVcVarsCall(const QString &varsBat, const QString &vars } } -void MsvcToolChain::setSupportedAbi(const Abi &abi) -{ - // Hack for Build Tools 2015 only. - QTC_CHECK(m_supportedAbis.isEmpty()); - m_supportedAbis = { abi }; -} - // -------------------------------------------------------------------------- // MsvcBasedToolChainConfigWidget: Creates a simple GUI without error label // to display name and varsBat. Derived classes should add the error label and @@ -1909,7 +1914,6 @@ static void detectCppBuildTools2015(QList *list) QLatin1String(e.varsBatArg)); tc->setDetection(ToolChain::AutoDetection); tc->setLanguage(language); - tc->setSupportedAbi(abi); list->append(tc); } } diff --git a/src/plugins/projectexplorer/msvctoolchain.h b/src/plugins/projectexplorer/msvctoolchain.h index 63d3e865529..bc0adb00bae 100644 --- a/src/plugins/projectexplorer/msvctoolchain.h +++ b/src/plugins/projectexplorer/msvctoolchain.h @@ -98,8 +98,6 @@ public: void setVarsBatArg(const QString &varsBA) { m_varsBatArg = varsBA; } void changeVcVarsCall(const QString &varsBat, const QString &varsBatArgs = QString()); - void setSupportedAbi(const Abi &abi); - bool operator==(const ToolChain &) const override; bool isJobCountSupported() const override { return false; } From 189ab38641d093ef1a987a985c3bbbe757118360 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 17 Oct 2019 10:54:12 +0200 Subject: [PATCH 09/57] macOS: Remove workaround for bug that was fixed in Qt 5.9.2 Removing the dummy OpenGL widget gets rid of flicker and scaling issues when moving between monitors with different DPI. Fixes: QTCREATORBUG-23064 Change-Id: I2373862244353b545e8756afe294f9beeefda422 Reviewed-by: Christian Stenger --- src/plugins/welcome/welcomeplugin.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/plugins/welcome/welcomeplugin.cpp b/src/plugins/welcome/welcomeplugin.cpp index 88a8a1ace4a..0b54b19b467 100644 --- a/src/plugins/welcome/welcomeplugin.cpp +++ b/src/plugins/welcome/welcomeplugin.cpp @@ -53,7 +53,6 @@ #include #include #include -#include #include #include #include @@ -353,12 +352,6 @@ WelcomeMode::WelcomeMode() layout->addWidget(new StyledBar(m_modeWidget)); layout->addItem(hbox); - if (Utils::HostOsInfo::isMacHost()) { // workaround QTBUG-61384 - auto openglWidget = new QOpenGLWidget; - openglWidget->hide(); - layout->addWidget(openglWidget); - } - setWidget(m_modeWidget); } From f68588a58581a3169375b998ec6cf57509388986 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 21 Oct 2019 09:24:51 +0200 Subject: [PATCH 10/57] RemoteLinux: Correct clean shutdown when debugging If the inferior stops by itself and the debugger tries to shutdown it had ended up waiting forever for the additional workers (e.g. ports gatherer, channel provider,...) to stop. The debugger appeared as finished but the runworker was still in a running state until the user would hit the stop button of the application output pane. Make the gdbserver essential to initiate a clean finish. Change-Id: I16b2ebe5feadc88bb76ce34b49ac5d3456d0867c Reviewed-by: hjk --- src/plugins/remotelinux/remotelinuxdebugsupport.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/remotelinux/remotelinuxdebugsupport.cpp b/src/plugins/remotelinux/remotelinuxdebugsupport.cpp index 5143efe7d95..a9a3eca3a1e 100644 --- a/src/plugins/remotelinux/remotelinuxdebugsupport.cpp +++ b/src/plugins/remotelinux/remotelinuxdebugsupport.cpp @@ -42,6 +42,7 @@ LinuxDeviceDebugSupport::LinuxDeviceDebugSupport(RunControl *runControl) addQmlServerInferiorCommandLineArgumentIfNeeded(); auto gdbServer = new GdbServerRunner(runControl, portsGatherer()); + gdbServer->setEssential(true); addStartDependency(gdbServer); From 1a6e441f1bfd9c0585970f5bc723e0190cb93603 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 22 Oct 2019 13:22:06 +0200 Subject: [PATCH 11/57] Locator: Ask before creating files With the option to not ask again. It's too easy to create unwanted files when mistyping names in Locator. Fixes: QTCREATORBUG-23078 Change-Id: I082d3e112db404813c7d8f46edb7a16836a98a92 Reviewed-by: Leena Miettinen Reviewed-by: David Schulz --- .../coreplugin/locator/filesystemfilter.cpp | 55 +++++++++++++++---- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index 5e04215539d..41ad77e5c1e 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -29,13 +29,17 @@ #include #include -#include #include +#include +#include #include +#include #include #include +#include #include +#include using namespace Core; using namespace Core::Internal; @@ -148,8 +152,12 @@ QList FileSystemFilter::matchesFor(QFutureInterface()); } +const char kAlwaysCreate[] = "Locator/FileSystemFilter/AlwaysCreate"; + void FileSystemFilter::accept(LocatorFilterEntry selection, - QString *newText, int *selectionStart, int *selectionLength) const + QString *newText, + int *selectionStart, + int *selectionLength) const { Q_UNUSED(selectionLength) QString fileName = selection.fileName; @@ -159,15 +167,42 @@ void FileSystemFilter::accept(LocatorFilterEntry selection, + QDir::toNativeSeparators(info.absoluteFilePath() + '/'); *newText = value; *selectionStart = value.length(); - return; - } else if (!info.exists()) { - QFile file(selection.internalData.toString()); - file.open(QFile::WriteOnly); - file.close(); + } else { + // Don't block locator filter execution with dialog + QTimer::singleShot(0, EditorManager::instance(), [info, selection] { + const QString targetFile = selection.internalData.toString(); + if (!info.exists()) { + if (Utils::CheckableMessageBox::shouldAskAgain(ICore::settings(), kAlwaysCreate)) { + Utils::CheckableMessageBox messageBox(ICore::dialogParent()); + messageBox.setWindowTitle(tr("Create File")); + messageBox.setIcon(QMessageBox::Question); + messageBox.setText( + tr("Create \"%1\"?") + .arg(Utils::FilePath::fromString(targetFile).shortNativePath())); + messageBox.setCheckBoxVisible(true); + messageBox.setCheckBoxText(tr("Always create")); + messageBox.setChecked(false); + messageBox.setStandardButtons(QDialogButtonBox::Cancel); + QPushButton *createButton = messageBox.addButton(tr("Create"), + QDialogButtonBox::AcceptRole); + messageBox.setDefaultButton(QDialogButtonBox::Cancel); + messageBox.exec(); + if (messageBox.clickedButton() != createButton) + return; + if (messageBox.isChecked()) + Utils::CheckableMessageBox::doNotAskAgain(ICore::settings(), kAlwaysCreate); + } + QFile file(targetFile); + file.open(QFile::WriteOnly); + file.close(); + } + const QFileInfo fileInfo(targetFile); + const QString cleanedFilePath = QDir::cleanPath(fileInfo.absoluteFilePath()); + EditorManager::openEditor(cleanedFilePath, + Id(), + EditorManager::CanContainLineAndColumnNumber); + }); } - const QFileInfo fileInfo(selection.internalData.toString()); - const QString cleanedFilePath = QDir::cleanPath(fileInfo.absoluteFilePath()); - EditorManager::openEditor(cleanedFilePath, Id(), EditorManager::CanContainLineAndColumnNumber); } bool FileSystemFilter::openConfigDialog(QWidget *parent, bool &needsRefresh) From 60bb13efbfb017faf0f68d04857010b27890ac8f Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 21 Oct 2019 15:51:02 +0200 Subject: [PATCH 12/57] QmlDesigner: Use DesignerWindowManager when reading stream Without the DesignerWindowManager QtQuick3D items will crash. Change-Id: Ib4057d581143aed860fa120ab189e11076d1f531 Reviewed-by: Miikka Heikkinen --- .../qml2puppet/instances/qt5nodeinstanceclientproxy.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp index 2ec58bbfbe3..dbee5969be4 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp @@ -55,6 +55,7 @@ Qt5NodeInstanceClientProxy::Qt5NodeInstanceClientProxy(QObject *parent) : { prioritizeDown(); if (QCoreApplication::arguments().at(1) == QLatin1String("--readcapturedstream")) { + DesignerSupport::activateDesignerWindowManager(); qputenv("DESIGNER_DONT_USE_SHARED_MEMORY", "1"); setNodeInstanceServer(new Qt5TestNodeInstanceServer(this)); initializeCapturedStream(QCoreApplication::arguments().at(2)); From 94ce6853c1a279622daf22455bfd2a8637fdd94b Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 22 Oct 2019 14:10:04 +0300 Subject: [PATCH 13/57] Fix widget order in import dialog so spinboxes can receive mouse focus The label needs to be created before the spinbox or the label will block the spinbox mouse events, as the tail end of the labels overlaps the non-checkbox control column to avoid unnecessary cutoff of the labels that do not have any non-checkbox controls. Change-Id: If7a7fd671b0dbb3f4c1ab5570217455e4978765e Reviewed-by: Thomas Hartmann Reviewed-by: Mahmoud Badri --- .../itemlibrary/itemlibraryassetimportdialog.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp index bfdbfe5c224..d7f84fddd10 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp @@ -298,6 +298,10 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option QJsonValue optValue = optObj.value("value"); QJsonArray conditions = optObj.value("conditions").toArray(); + auto *optLabel = new QLabel(optionsAreaContents); + optLabel->setText(optName); + optLabel->setToolTip(optDesc); + QWidget *optControl = nullptr; if (optType == "Boolean") { auto *optCheck = new QCheckBox(optionsAreaContents); @@ -346,15 +350,11 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option qWarning() << __FUNCTION__ << "Unsupported option type:" << optType; continue; } + optControl->setToolTip(optDesc); if (!conditions.isEmpty()) conditionMap.insert(optKey, conditions); - auto *optLabel = new QLabel(optionsAreaContents); - optLabel->setText(optName); - optLabel->setToolTip(optDesc); - optControl->setToolTip(optDesc); - const QString &groupName = optionToGroupMap.value(optKey); if (!groupName.isEmpty() && groupIndexMap.contains(groupName)) widgets[groupIndexMap[groupName]].append({optLabel, optControl}); From 4eb51a66ac257708ac6c0d45729a516aff1d6565 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 22 Oct 2019 13:02:16 +0300 Subject: [PATCH 14/57] Fix light type in edit view Light component was split into three different light types in Quick3D. Change-Id: I409dc4888b389bcb9b8e842f3a6bfeac34f3aaa0 Reviewed-by: Thomas Hartmann Reviewed-by: Mahmoud Badri --- share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml index d3b693788a3..73f4846e9cb 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml @@ -60,11 +60,10 @@ Window { enableAxisLines: false } - Light { + PointLight { id: pointLight visible: showEditLight position: editCamera.position - lightType: Light.Point } Camera { From 30b37a989ab351f3a8b52c659ea51fa149471342 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 22 Oct 2019 17:12:20 +0300 Subject: [PATCH 15/57] Ignore asset file suffix case when importing 3D assets Change-Id: Ic742f5c6bec82718d99d472a26271cf500594e63 Reviewed-by: Mahmoud Badri Reviewed-by: Thomas Hartmann --- .../components/itemlibrary/itemlibraryassetimportdialog.cpp | 2 +- .../components/itemlibrary/itemlibraryassetimporter.cpp | 2 +- .../qmldesigner/components/itemlibrary/itemlibrarywidget.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp index d7f84fddd10..3f403d03133 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp @@ -165,7 +165,7 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im QMap tabMap; // QMap used for alphabetical order for (const auto &file : qAsConst(m_quick3DFiles)) { auto extIt = supportedExtensions.constBegin(); - QString ext = QFileInfo(file).suffix(); + QString ext = QFileInfo(file).suffix().toLower(); while (extIt != supportedExtensions.constEnd()) { if (!tabMap.contains(extIt.key()) && extIt.value().contains(ext)) { tabMap.insert(extIt.key(), m_extToImportOptionsMap.value(ext)); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp index ac40e87c791..d4f1d090baf 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp @@ -173,7 +173,7 @@ bool ItemLibraryAssetImporter::isQuick3DAsset(const QString &fileName) const for (const auto &ext : exts) quick3DExt << ext; } - return quick3DExt.contains(QFileInfo(fileName).suffix()); + return quick3DExt.contains(QFileInfo(fileName).suffix().toLower()); #else Q_UNUSED(fileName) return false; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index 8010ed61075..a24cfc731e2 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -517,7 +517,7 @@ void ItemLibraryWidget::addResources() QMultiMap partitionedFileNames; for (const QString &fileName : fileNames) { - const QString suffix = "*." + QFileInfo(fileName).suffix(); + const QString suffix = "*." + QFileInfo(fileName).suffix().toLower(); const QString category = reverseMap.value(suffix); partitionedFileNames.insert(category, fileName); } From a4863bd2380abe9b2ba525ed36d6a97436ba1d44 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 22 Oct 2019 17:36:32 +0200 Subject: [PATCH 16/57] "Add Library" wizard: Fix display glitch Fixes: QTCREATORBUG-23049 Change-Id: Ic7e694707e6e0565866b86838f1302719a933854 Reviewed-by: Eike Ziller --- .../qmakeprojectmanager/addlibrarywizard.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/plugins/qmakeprojectmanager/addlibrarywizard.cpp b/src/plugins/qmakeprojectmanager/addlibrarywizard.cpp index 998a33fdddc..34553567b94 100644 --- a/src/plugins/qmakeprojectmanager/addlibrarywizard.cpp +++ b/src/plugins/qmakeprojectmanager/addlibrarywizard.cpp @@ -30,9 +30,10 @@ #include #include -#include -#include #include +#include +#include +#include #include #include @@ -268,11 +269,18 @@ SummaryPage::SummaryPage(AddLibraryWizard *parent) setFinalPage(true); auto *layout = new QVBoxLayout(this); + const auto scrollArea = new QScrollArea; + const auto snippetWidget = new QWidget; + const auto snippetLayout = new QVBoxLayout(snippetWidget); m_summaryLabel = new QLabel(this); m_snippetLabel = new QLabel(this); m_snippetLabel->setWordWrap(true); layout->addWidget(m_summaryLabel); - layout->addWidget(m_snippetLabel); + snippetLayout->addWidget(m_snippetLabel); + snippetLayout->addStretch(1); + scrollArea->setWidget(snippetWidget); + scrollArea->setWidgetResizable(true); + layout->addWidget(scrollArea); m_summaryLabel->setTextFormat(Qt::RichText); m_snippetLabel->setTextFormat(Qt::RichText); m_snippetLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); From 313d16bba4d56b257b14ac48aa4a5edb26b78636 Mon Sep 17 00:00:00 2001 From: Richard Weickelt Date: Sun, 20 Oct 2019 21:31:31 +0200 Subject: [PATCH 17/57] Update Qbs module [ChangeLog] Updated Qbs to version 1.15.0. Change-Id: I542fe7a7eb5e60fe6138213e04b69356c02d7a0c Reviewed-by: Christian Kandeler --- src/shared/qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/qbs b/src/shared/qbs index aec975a3f95..a703c788abc 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit aec975a3f95f905b2d63ea1500ace28eddea7b9e +Subproject commit a703c788abc0035bafe53a05370900db0a3ac43c From 608bbccc63169a698616057de2673d37d44dc866 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 23 Oct 2019 12:01:47 +0200 Subject: [PATCH 18/57] Revert "Enable visibility settings for binaries" and fixup Since we are currently not able to fix the build with all build system and platform combinations this partially reverts commit b128d498b2da55a9f87cd2eabb802acc0c48e7d4 and 6463a686f6b6530c005fe6b340152b331bca9600 Change-Id: Icfb9ab6096ad1204e595522be12146b91d570f49 Reviewed-by: Orgad Shaneh Reviewed-by: Christian Stenger --- src/shared/qtcreator_gui_pch.h | 13 +++++++-- src/shared/qtcreator_pch.h | 50 +++++++++++++--------------------- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/src/shared/qtcreator_gui_pch.h b/src/shared/qtcreator_gui_pch.h index 9ac491898b9..b25dbf67b70 100644 --- a/src/shared/qtcreator_gui_pch.h +++ b/src/shared/qtcreator_gui_pch.h @@ -32,7 +32,16 @@ #if defined __cplusplus -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #endif diff --git a/src/shared/qtcreator_pch.h b/src/shared/qtcreator_pch.h index a80eb42e7a6..4988f3d9392 100644 --- a/src/shared/qtcreator_pch.h +++ b/src/shared/qtcreator_pch.h @@ -29,38 +29,26 @@ */ #if defined __cplusplus -#include +#include -#ifdef Q_OS_WIN -#define WIN32_LEAN_AND_MEAN - -// lib/Utils needs defines for Windows 8 -#ifdef Q_CC_MINGW -#define WINVER _WIN32_WINNT_WIN8 -#define _WIN32_WINNT _WIN32_WINNT_WIN8 -#endif // Q_CC_MINGW -#define NOHELP -#include - -#undef DELETE -#undef IN -#undef OUT -#undef ERROR -#undef ABSOLUTE - -//QT_NO_FLOAT16_OPERATORS is used on Visual Studio 2017 (and earlier): -//when including and in the same translation unit, -//it would cause a compilation error due to a toolchain bug (see [QTBUG-72073]) -#if _MSC_VER <= 1920 -#define QT_NO_FLOAT16_OPERATORS +#ifdef Q_WS_WIN +# define _POSIX_ +# include +# undef _POSIX_ #endif -#define _POSIX_ -#include -#undef _POSIX_ -#endif // Q_OS_WIN - -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include @@ -71,7 +59,7 @@ using Qt::dec; using Qt::showbase; using Qt::hex; using Qt::noforcesign; -#endif //QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +#endif #include -#endif //defined __cplusplus +#endif From fdca8f62658175c7a8a95cd7b31081014eb1928c Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 1 Oct 2019 15:07:40 +0200 Subject: [PATCH 19/57] Qnx: Fix progress bar in Qt library deployment dialog Amends d7178b88c4. Task-number: QTCREATORBUG-22885 Change-Id: Ic60e37382073c9d867afa93b28c7cf3df423fb25 Reviewed-by: hjk --- src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp index 4182ca28264..2e3f9c2d4d9 100644 --- a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp +++ b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp @@ -169,12 +169,11 @@ void QnxDeployQtLibrariesDialog::updateProgress(const QString &progressMessage) { QTC_CHECK(m_state == Uploading); - if (!progressMessage.startsWith(QLatin1String("Uploading file"))) - return; - - ++m_progressCount; - - m_ui->deployProgress->setValue(m_progressCount); + const int progress = progressMessage.count("sftp> put"); + if (progress != 0) { + m_progressCount += progress; + m_ui->deployProgress->setValue(m_progressCount); + } } void QnxDeployQtLibrariesDialog::handleUploadFinished() From 40f02011b08b4d525acd8804c53aa37cbdb6008e Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 17 Oct 2019 17:58:22 +0200 Subject: [PATCH 20/57] Fix some memory leaks Found by Address Sanitizer. Change-Id: I989da71e24d737e36a88b83a1f382ce2d67e3307 Reviewed-by: hjk --- .../baremetal/gdbserverprovidermanager.cpp | 1 + src/plugins/debugger/debuggermainwindow.cpp | 6 ++++++ .../debuggerrunconfigurationaspect.cpp | 8 ++++++++ .../debugger/debuggerrunconfigurationaspect.h | 1 + .../jsonwizard/jsonwizard_test.cpp | 18 +++++++++++------- .../projectexplorer/projectexplorer.cpp | 4 ++++ src/plugins/projectexplorer/projectexplorer.h | 1 + .../projectexplorer/targetsetuppage.cpp | 1 + .../toolchainsettingsaccessor.cpp | 7 ++++++- 9 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/plugins/baremetal/gdbserverprovidermanager.cpp b/src/plugins/baremetal/gdbserverprovidermanager.cpp index 16758ee30ce..cd4f199508f 100644 --- a/src/plugins/baremetal/gdbserverprovidermanager.cpp +++ b/src/plugins/baremetal/gdbserverprovidermanager.cpp @@ -77,6 +77,7 @@ GdbServerProviderManager::~GdbServerProviderManager() { qDeleteAll(m_providers); m_providers.clear(); + qDeleteAll(m_factories); delete m_writer; m_instance = nullptr; } diff --git a/src/plugins/debugger/debuggermainwindow.cpp b/src/plugins/debugger/debuggermainwindow.cpp index b77a2536a6b..ce01d5a5a9e 100644 --- a/src/plugins/debugger/debuggermainwindow.cpp +++ b/src/plugins/debugger/debuggermainwindow.cpp @@ -131,6 +131,7 @@ class DebuggerMainWindowPrivate : public QObject { public: DebuggerMainWindowPrivate(DebuggerMainWindow *parent); + ~DebuggerMainWindowPrivate(); void selectPerspective(Perspective *perspective); void depopulateCurrentPerspective(); @@ -256,6 +257,11 @@ DebuggerMainWindowPrivate::DebuggerMainWindowPrivate(DebuggerMainWindow *parent) }); } +DebuggerMainWindowPrivate::~DebuggerMainWindowPrivate() +{ + delete m_editorPlaceHolder; +} + DebuggerMainWindow::DebuggerMainWindow() : d(new DebuggerMainWindowPrivate(this)) { diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp index b7a6c697cfb..702fe98c84c 100644 --- a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp +++ b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp @@ -220,6 +220,14 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target) m_overrideStartupAspect->setLabelText(tr("Additional startup commands:")); } +DebuggerRunConfigurationAspect::~DebuggerRunConfigurationAspect() +{ + delete m_cppAspect; + delete m_qmlAspect; + delete m_multiProcessAspect; + delete m_overrideStartupAspect; +} + void DebuggerRunConfigurationAspect::setUseQmlDebugger(bool value) { m_qmlAspect->setValue(value); diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.h b/src/plugins/debugger/debuggerrunconfigurationaspect.h index e34185d39e4..58619ee3ef1 100644 --- a/src/plugins/debugger/debuggerrunconfigurationaspect.h +++ b/src/plugins/debugger/debuggerrunconfigurationaspect.h @@ -42,6 +42,7 @@ class DEBUGGER_EXPORT DebuggerRunConfigurationAspect public: DebuggerRunConfigurationAspect(ProjectExplorer::Target *target); + ~DebuggerRunConfigurationAspect(); void fromMap(const QVariantMap &map) override; void toMap(QVariantMap &map) const override; diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard_test.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizard_test.cpp index 9a5947cdd1b..073432ab26c 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizard_test.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard_test.cpp @@ -94,12 +94,16 @@ auto findComboBox(Utils::Wizard *wizard, const QString &objectName) { }; } // namespace + +struct FactoryDeleter { void operator()(ProjectExplorer::JsonWizardFactory *f) { f->deleteLater(); } }; +using FactoryPtr = std::unique_ptr; + void ProjectExplorer::ProjectExplorerPlugin::testJsonWizardsEmptyWizard() { QString errorMessage; const QJsonObject wizard = createGeneralWizard(QJsonObject()); - JsonWizardFactory *factory = ProjectExplorer::JsonWizardFactory::createWizardFactory(wizard.toVariantMap(), QDir(), &errorMessage); + const FactoryPtr factory(ProjectExplorer::JsonWizardFactory::createWizardFactory(wizard.toVariantMap(), QDir(), &errorMessage)); QVERIFY(factory == nullptr); QCOMPARE(qPrintable(errorMessage), "Page has no typeId set."); } @@ -110,7 +114,7 @@ void ProjectExplorer::ProjectExplorerPlugin::testJsonWizardsEmptyPage() const QJsonObject pages = createFieldPageJsonObject(QJsonArray()); const QJsonObject wizard = createGeneralWizard(pages); - JsonWizardFactory *factory = ProjectExplorer::JsonWizardFactory::createWizardFactory(wizard.toVariantMap(), QDir(), &errorMessage); + const FactoryPtr factory(JsonWizardFactory::createWizardFactory(wizard.toVariantMap(), QDir(), &errorMessage)); QVERIFY(factory == nullptr); QCOMPARE(qPrintable(errorMessage), "When parsing fields of page \"PE.Wizard.Page.Fields\": "); } @@ -143,7 +147,7 @@ void ProjectExplorer::ProjectExplorerPlugin::testJsonWizardsUnusedKeyAtFields() const QJsonObject wizard = createGeneralWizard(pages); QTest::ignoreMessage(QtWarningMsg, QRegularExpression("has unsupported keys: wrong")); - JsonWizardFactory *factory = ProjectExplorer::JsonWizardFactory::createWizardFactory(wizard.toVariantMap(), QDir(), &errorMessage); + const FactoryPtr factory(JsonWizardFactory::createWizardFactory(wizard.toVariantMap(), QDir(), &errorMessage)); QVERIFY(factory); QVERIFY(errorMessage.isEmpty()); } @@ -166,7 +170,7 @@ void ProjectExplorer::ProjectExplorerPlugin::testJsonWizardsCheckBox() }); const QJsonObject pages = createFieldPageJsonObject(widgets); const QJsonObject wizardObject = createGeneralWizard(pages); - JsonWizardFactory *factory = ProjectExplorer::JsonWizardFactory::createWizardFactory(wizardObject.toVariantMap(), QDir(), &errorMessage); + const FactoryPtr factory(JsonWizardFactory::createWizardFactory(wizardObject.toVariantMap(), QDir(), &errorMessage)); QVERIFY2(factory, qPrintable(errorMessage)); Utils::Wizard *wizard = factory->runWizard(QString(), &parent, Core::Id(), QVariantMap()); @@ -198,7 +202,7 @@ void ProjectExplorer::ProjectExplorerPlugin::testJsonWizardsLineEdit() }); const QJsonObject pages = createFieldPageJsonObject(widgets); const QJsonObject wizardObject = createGeneralWizard(pages); - JsonWizardFactory *factory = ProjectExplorer::JsonWizardFactory::createWizardFactory(wizardObject.toVariantMap(), QDir(), &errorMessage); + const FactoryPtr factory(JsonWizardFactory::createWizardFactory(wizardObject.toVariantMap(), QDir(), &errorMessage)); QVERIFY2(factory, qPrintable(errorMessage)); Utils::Wizard *wizard = factory->runWizard(QString(), &parent, Core::Id(), QVariantMap()); @@ -227,7 +231,7 @@ void ProjectExplorer::ProjectExplorerPlugin::testJsonWizardsComboBox() const QJsonObject pages = createFieldPageJsonObject(widgets); const QJsonObject wizardObject = createGeneralWizard(pages); - JsonWizardFactory *factory = ProjectExplorer::JsonWizardFactory::createWizardFactory(wizardObject.toVariantMap(), QDir(), &errorMessage); + const FactoryPtr factory(JsonWizardFactory::createWizardFactory(wizardObject.toVariantMap(), QDir(), &errorMessage)); QVERIFY2(factory, qPrintable(errorMessage)); Utils::Wizard *wizard = factory->runWizard(QString(), &parent, Core::Id(), QVariantMap()); @@ -285,7 +289,7 @@ void ProjectExplorer::ProjectExplorerPlugin::testJsonWizardsIconList() const QJsonObject pages = createFieldPageJsonObject(widgets); const QJsonObject wizardObject = createGeneralWizard(pages); - JsonWizardFactory *factory = ProjectExplorer::JsonWizardFactory::createWizardFactory(wizardObject.toVariantMap(), QDir(), &errorMessage); + const FactoryPtr factory(JsonWizardFactory::createWizardFactory(wizardObject.toVariantMap(), QDir(), &errorMessage)); QVERIFY2(factory, qPrintable(errorMessage)); Utils::Wizard *wizard = factory->runWizard(QString(), &parent, Core::Id(), QVariantMap()); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 439e5f03a5a..0880e3c3e5d 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -639,6 +639,10 @@ ProjectExplorerPlugin::~ProjectExplorerPlugin() delete dd; dd = nullptr; m_instance = nullptr; + +#ifdef WITH_TESTS + deleteTestToolchains(); +#endif } ProjectExplorerPlugin *ProjectExplorerPlugin::instance() diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h index 32531e094b8..feb53ccdef2 100644 --- a/src/plugins/projectexplorer/projectexplorer.h +++ b/src/plugins/projectexplorer/projectexplorer.h @@ -243,6 +243,7 @@ private slots: void testToolChainMerging_data(); void testToolChainMerging(); + void deleteTestToolchains(); void testUserFileAccessor_prepareToReadSettings(); void testUserFileAccessor_prepareToReadSettingsObsoleteVersion(); diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp index 2895a2983e5..ff317be5e6e 100644 --- a/src/plugins/projectexplorer/targetsetuppage.cpp +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -241,6 +241,7 @@ TargetSetupPage::~TargetSetupPage() { disconnect(); reset(); + delete m_spacer; delete m_ui; } diff --git a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp index ea5a07f0fe1..78fafb5ea75 100644 --- a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp +++ b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp @@ -309,7 +309,7 @@ public: setTypeDisplayName("Test Tool Chain"); } - static QList toolChains(); + static QList toolChains() { return m_toolChains; } static bool hasToolChains() { return !m_toolChains.isEmpty(); } Abi targetAbi() const override { return Abi::hostAbi(); } @@ -507,6 +507,11 @@ void ProjectExplorerPlugin::testToolChainMerging() Utils::toSet(ops.toRegister + ops.toDemote + ops.toDelete)); } +void ProjectExplorerPlugin::deleteTestToolchains() +{ + qDeleteAll(TTC::toolChains()); +} + } // namespace ProjectExplorer #endif // WITH_TESTS From 07573de10269af898518b4d8e74278b3a925c05c Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 23 Oct 2019 15:16:06 +0200 Subject: [PATCH 21/57] QmlDesigner: Do not crash if EditView3D contains errors EditView3D.qml can contain errors, most likely because of QtQuick3D updates. Change-Id: I85879d9079ba8771a2af4478ba2e4e63a6aa9223 Reviewed-by: Miikka Heikkinen --- .../instances/qt5informationnodeinstanceserver.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index d0931da3e04..9413c74c0cb 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -84,6 +84,11 @@ static QObject *createEditView3D(QQmlEngine *engine) QWindow *window = qobject_cast(component.create()); + if (!window) { + qWarning() << "Could not create edit view" << component.errors(); + return nullptr; + } + //For macOS we have to use the 4.1 core profile QSurfaceFormat surfaceFormat = window->requestedFormat(); surfaceFormat.setVersion(4, 1); @@ -193,6 +198,9 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QListsetParent(view); sceneProperty.write(objectToVariant(node)); From 0ddd473cc026c2e4d33ac1a65ee8ffdeb9ac85af Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 23 Oct 2019 16:29:30 +0200 Subject: [PATCH 22/57] Target setup page: Handle slow kit manager It has been observed by users (though not reproduced here) that the target setup page would apparently appear before the kit manager was finished setting up the initial kits, leading to an empty kit list on the target setup page even after the kits were finally loaded. We now take this possibility into account. Fixes: QTCREATORBUG-22353 Change-Id: I83cdc3da45785c3badfac484a54f34859191cc37 Reviewed-by: hjk --- .../projectexplorer/targetsetuppage.cpp | 21 +++++++++++++------ src/plugins/projectexplorer/targetsetuppage.h | 2 ++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp index ff317be5e6e..d80b2689c16 100644 --- a/src/plugins/projectexplorer/targetsetuppage.cpp +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -209,12 +209,12 @@ TargetSetupPage::TargetSetupPage(QWidget *parent) : void TargetSetupPage::initializePage() { - reset(); - - setupWidgets(); - setupImports(); - selectAtLeastOneKit(); - updateVisibility(); + if (KitManager::isLoaded()) { + doInitializePage(); + } else { + connect(KitManager::instance(), &KitManager::kitsLoaded, + this, &TargetSetupPage::doInitializePage); + } } void TargetSetupPage::setRequiredKitPredicate(const Kit::Predicate &predicate) @@ -494,6 +494,15 @@ void TargetSetupPage::kitFilterChanged(const QString &filterText) selectAtLeastOneKit(); } +void TargetSetupPage::doInitializePage() +{ + reset(); + setupWidgets(); + setupImports(); + selectAtLeastOneKit(); + updateVisibility(); +} + void TargetSetupPage::changeAllKitsSelections() { if (m_ui->allKitsCheckBox->checkState() == Qt::PartiallyChecked) diff --git a/src/plugins/projectexplorer/targetsetuppage.h b/src/plugins/projectexplorer/targetsetuppage.h index c0814a1ce48..e8cc7aef9e6 100644 --- a/src/plugins/projectexplorer/targetsetuppage.h +++ b/src/plugins/projectexplorer/targetsetuppage.h @@ -87,6 +87,8 @@ public: void kitFilterChanged(const QString &filterText); private: + void doInitializePage(); + void handleKitAddition(Kit *k); void handleKitRemoval(Kit *k); void handleKitUpdate(Kit *k); From 946943203566167a2f8d3e785d6250ed8a8a87cd Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 23 Oct 2019 16:29:31 +0200 Subject: [PATCH 23/57] QmlDesigner: Add Qt5InformationNodeInstanceServer::modifyProperties() This method allows to modify properties in the data model from the puppet. For performance reasons, properties should be modified in bulks. Each bulk will be one step on the undo stack. Change-Id: I7dbef02781706c8638981512ca0ec45d24c54545 Reviewed-by: Miikka Heikkinen Reviewed-by: Thomas Hartmann --- .../instances/nodeinstanceserver.cpp | 25 +++++++++++++++++++ .../qml2puppet/instances/nodeinstanceserver.h | 7 ++++++ .../qt5informationnodeinstanceserver.cpp | 9 +++++++ .../qt5informationnodeinstanceserver.h | 1 + 4 files changed, 42 insertions(+) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp index bd293488f19..9103ef5de01 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp @@ -1190,6 +1190,31 @@ ValuesChangedCommand NodeInstanceServer::createValuesChangedCommand(const QVecto return ValuesChangedCommand(valueVector); } +ValuesModifiedCommand NodeInstanceServer::createValuesModifiedCommand( + const QVector &propertyList) const +{ + QVector valueVector; + + for (const InstancePropertyValueTriple &property : propertyList) { + const PropertyName propertyName = property.propertyName; + const ServerNodeInstance instance = property.instance; + const QVariant propertyValue = property.propertyValue; + + if (instance.isValid()) { + if (QMetaType::isRegistered(propertyValue.userType()) + && supportedVariantType(propertyValue.type())) { + valueVector.append(PropertyValueContainer(instance.instanceId(), + propertyName, + propertyValue, + PropertyName())); + } + } + } + + return ValuesModifiedCommand(valueVector); +} + + QByteArray NodeInstanceServer::importCode() const { return m_importCode; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h index 65c2bdfac14..7af63c0b5be 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h @@ -60,6 +60,7 @@ namespace QmlDesigner { class NodeInstanceClientInterface; class ValuesChangedCommand; +class ValuesModifiedCommand; class PixmapChangedCommand; class InformationChangedCommand; class ChildrenChangedCommand; @@ -82,6 +83,11 @@ public: using IdPropertyPair = QPair; using InstancePropertyPair= QPair; using DummyPair = QPair >; + using InstancePropertyValueTriple = struct { + ServerNodeInstance instance; + PropertyName propertyName; + QVariant propertyValue; + }; explicit NodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient); @@ -168,6 +174,7 @@ protected: ValuesChangedCommand createValuesChangedCommand(const QList &instanceList) const; ValuesChangedCommand createValuesChangedCommand(const QVector &propertyList) const; + ValuesModifiedCommand createValuesModifiedCommand(const QVector &propertyList) const; PixmapChangedCommand createPixmapChangedCommand(const QList &instanceList) const; InformationChangedCommand createAllInformationChangedCommand(const QList &instanceList, bool initial = false) const; ChildrenChangedCommand createChildrenChangedCommand(const ServerNodeInstance &parentInstance, const QList &instanceList) const; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 9413c74c0cb..b8aabfffc76 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -165,6 +165,15 @@ void Qt5InformationNodeInstanceServer::selectInstance(const ServerNodeInstance & nodeInstanceClient()->selectionChanged(createChangeSelectionCommand({instance})); } +/* This method allows changing property values from the puppet + * For performance reasons (and the undo stack) properties should always be modifed in 'bulks'. + */ +void Qt5InformationNodeInstanceServer::modifyProperties( + const QVector &properties) +{ + nodeInstanceClient()->valuesModified(createValuesModifiedCommand(properties)); +} + QObject *Qt5InformationNodeInstanceServer::findRootNodeOf3DViewport( const QList &instanceList) const { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index 962336ccdc4..6f05659426e 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -51,6 +51,7 @@ protected: bool isDirtyRecursiveForNonInstanceItems(QQuickItem *item) const; bool isDirtyRecursiveForParentInstances(QQuickItem *item) const; void selectInstance(const ServerNodeInstance &instance); + void modifyProperties(const QVector &properties); private: void setup3DEditView(const QList &instanceList); From 3c78d4d74d69ab44e49d6c3d854abf12ab2b2d3a Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Wed, 23 Oct 2019 15:40:55 +0300 Subject: [PATCH 24/57] Enable object selection in the 3D edit view Clicking an object in the 3D object selection view, selects it in the creator side. Multiselection (i.e. Ctrl+click) is not implemented yet. Also selected object is not highlighted in the view yet. Task-number: QDS-1124 Change-Id: I0b10162539ecedc40ed117896e385975c52b04a9 Reviewed-by: Miikka Heikkinen --- .../qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml | 11 +++++++++++ .../instances/qt5informationnodeinstanceserver.cpp | 9 ++++++++- .../instances/qt5informationnodeinstanceserver.h | 4 ++++ .../designercore/instances/nodeinstanceview.cpp | 2 +- 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml index 73f4846e9cb..f3c7dc3429e 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml @@ -42,12 +42,23 @@ Window { property alias showEditLight: editLightCheckbox.checked property alias usePerspective: usePerspectiveCheckbox.checked + signal objectClicked(var object) + Rectangle { id: sceneBg color: "#FFFFFF" anchors.fill: parent focus: true + TapHandler { // check tapping/clicking an object in the scene + onTapped: { + var pickResult = editView.pick(eventPoint.scenePosition.x, + eventPoint.scenePosition.y); + if (pickResult.objectHit) + viewWindow.objectClicked(pickResult.objectHit); + } + } + View3D { id: editView anchors.fill: parent diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index b8aabfffc76..ff4bb7e84dd 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -75,7 +75,7 @@ static QVariant objectToVariant(QObject *object) return QVariant::fromValue(object); } -static QObject *createEditView3D(QQmlEngine *engine) +QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine) { QmlDesigner::Internal::CameraControlHelper *helper = new QmlDesigner::Internal::CameraControlHelper(); engine->rootContext()->setContextProperty("designStudioNativeCameraControlHelper", helper); @@ -89,6 +89,8 @@ static QObject *createEditView3D(QQmlEngine *engine) return nullptr; } + QObject::connect(window, SIGNAL(objectClicked(QVariant)), this, SLOT(objectClicked(QVariant))); + //For macOS we have to use the 4.1 core profile QSurfaceFormat surfaceFormat = window->requestedFormat(); surfaceFormat.setVersion(4, 1); @@ -99,6 +101,11 @@ static QObject *createEditView3D(QQmlEngine *engine) return window; } +void Qt5InformationNodeInstanceServer::objectClicked(const QVariant &object) { + QObject *item = qobject_cast(object.value()); + selectInstance(instanceForObject(item)); +} + Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) : Qt5NodeInstanceServer(nodeInstanceClient) { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index 6f05659426e..2e39339583a 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -44,6 +44,9 @@ public: void removeSharedMemory(const RemoveSharedMemoryCommand &command) override; void changeSelection(const ChangeSelectionCommand &command) override; +public slots: + void objectClicked(const QVariant &object); + protected: void collectItemChangesAndSendChangeCommands() override; void sendChildrenChangedCommand(const QList &childList); @@ -54,6 +57,7 @@ protected: void modifyProperties(const QVector &properties); private: + QObject *createEditView3D(QQmlEngine *engine); void setup3DEditView(const QList &instanceList); QObject *findRootNodeOf3DViewport(const QList &instanceList) const; diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 7200231267a..ed63caec5ac 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -1329,7 +1329,6 @@ void NodeInstanceView::childrenChanged(const ChildrenChangedCommand &command) if (!model()) return; - QVector childNodeVector; foreach (qint32 instanceId, command.childrenInstances()) { @@ -1396,6 +1395,7 @@ void NodeInstanceView::sendToken(const QString &token, int number, const QVector void NodeInstanceView::selectionChanged(const ChangeSelectionCommand &command) { + clearSelectedModelNodes(); foreach (const qint32 &instanceId, command.instanceIds()) { if (hasModelNodeForInternalId(instanceId)) selectModelNode(modelNodeForInternalId(instanceId)); From 99deb21b7aa81d6a5d6036af2a5022ede2c07052 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 30 Sep 2019 11:14:19 +0200 Subject: [PATCH 25/57] Squish: Adapt verification of kits Kits are nowadays displayed if configured, but disabled if they do not fit for the respective project. Change-Id: If04a20afde2fc1ada643e45d5eea33e6ace7a4f1 Reviewed-by: Christian Stenger Reviewed-by: Robert Loehning --- tests/system/shared/utils.py | 4 ++-- tests/system/suite_general/tst_create_proj_wizard/test.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/system/shared/utils.py b/tests/system/shared/utils.py index ef46aca7b26..6501f738a2c 100644 --- a/tests/system/shared/utils.py +++ b/tests/system/shared/utils.py @@ -391,9 +391,9 @@ def getConfiguredKits(): test.log("Configured kits: %s" % str(result)) return result -def visibleCheckBoxExists(text): +def enabledCheckBoxExists(text): try: - findObject("{type='QCheckBox' text='%s' visible='1'}" % text) + waitForObject("{type='QCheckBox' text='%s'}" % text, 100) return True except: return False diff --git a/tests/system/suite_general/tst_create_proj_wizard/test.py b/tests/system/suite_general/tst_create_proj_wizard/test.py index 69a69ace30a..1d822c7ca59 100644 --- a/tests/system/suite_general/tst_create_proj_wizard/test.py +++ b/tests/system/suite_general/tst_create_proj_wizard/test.py @@ -93,7 +93,7 @@ def main(): def verifyKitCheckboxes(kits, displayedPlatforms): waitForObject("{type='QLabel' unnamed='1' visible='1' text='Kit Selection'}") - availableCheckboxes = frozenset(filter(visibleCheckBoxExists, kits.keys())) + availableCheckboxes = frozenset(filter(enabledCheckBoxExists, kits.keys())) # verification whether expected, found and configured match expectedShownKits = availableCheckboxes.intersection(displayedPlatforms) From 1641ad625eed284a43ccf9b8ea2f9cb9649a095d Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Thu, 24 Oct 2019 12:48:27 +0300 Subject: [PATCH 26/57] Deselect all objects when clicking an empty point in the 3D edit view Task-number: QDS-1124 Change-Id: I5a9ed39a69c467de27dd7c4564d53b7bf033dd92 Reviewed-by: Miikka Heikkinen Reviewed-by: Thomas Hartmann --- share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml | 3 +-- .../instances/qt5informationnodeinstanceserver.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml index f3c7dc3429e..b9849d484c8 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml @@ -54,8 +54,7 @@ Window { onTapped: { var pickResult = editView.pick(eventPoint.scenePosition.x, eventPoint.scenePosition.y); - if (pickResult.objectHit) - viewWindow.objectClicked(pickResult.objectHit); + viewWindow.objectClicked(pickResult.objectHit); } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index ff4bb7e84dd..685136cb2d4 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -101,9 +101,10 @@ QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine) return window; } -void Qt5InformationNodeInstanceServer::objectClicked(const QVariant &object) { - QObject *item = qobject_cast(object.value()); - selectInstance(instanceForObject(item)); +// an object is clicked in the 3D edit view +void Qt5InformationNodeInstanceServer::objectClicked(const QVariant &object) +{ + selectInstance(instanceForObject(object.value())); } Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) : From d53d874224381a184b2b160240e307616a39d3d1 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Fri, 18 Oct 2019 15:16:01 +0200 Subject: [PATCH 27/57] add assetimporters as a new QtQuickDesigner depdency This is used to import QtQuick3d content as resources in the designer. Not sure if we need the qtmodule QtQuick3d in QtCreator if QtCreator also want to offer that functionality Change-Id: I7b50b820916dbe0bc0a0fc6dedc29fcb08d54f3b Reviewed-by: Eike Ziller --- scripts/deployqt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/deployqt.py b/scripts/deployqt.py index 2b98e3ca421..5e4808a211a 100755 --- a/scripts/deployqt.py +++ b/scripts/deployqt.py @@ -323,7 +323,7 @@ def main(): QT_INSTALL_QML = qt_install_info['QT_INSTALL_QML'] QT_INSTALL_TRANSLATIONS = qt_install_info['QT_INSTALL_TRANSLATIONS'] - plugins = ['accessible', 'codecs', 'designer', 'iconengines', 'imageformats', 'platformthemes', + plugins = ['assetimporters', 'accessible', 'codecs', 'designer', 'iconengines', 'imageformats', 'platformthemes', 'platforminputcontexts', 'platforms', 'printsupport', 'qmltooling', 'sqldrivers', 'styles', 'xcbglintegrations', 'wayland-decoration-client', From 659ba2f8921c8f968eaa1ed610135563fdf76d53 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 24 Oct 2019 16:32:35 +0200 Subject: [PATCH 28/57] WebAssembly: Set a restriction checker for WebAssembly Qt Versions Task-number: QTCREATORBUG-22828 Change-Id: Ifaf1624b1fb53b4a9a58883b6b968fff2ae8fab6 Reviewed-by: Christian Kandeler --- src/plugins/webassembly/webassemblyqtversion.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/webassembly/webassemblyqtversion.cpp b/src/plugins/webassembly/webassemblyqtversion.cpp index 54f51be4bb4..ba1b0a76999 100644 --- a/src/plugins/webassembly/webassemblyqtversion.cpp +++ b/src/plugins/webassembly/webassemblyqtversion.cpp @@ -59,6 +59,9 @@ WebAssemblyQtVersionFactory::WebAssemblyQtVersionFactory() setQtVersionCreator([] { return new WebAssemblyQtVersion; }); setSupportedType(Constants::WEBASSEMBLY_QT_VERSION); setPriority(1); + setRestrictionChecker([](const SetupData &setup) { + return setup.platforms.contains("wasm"); + }); } } // namespace Internal From bf698f5a2f8495158a218a310ba0d901629860fd Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 24 Oct 2019 07:48:43 +0200 Subject: [PATCH 29/57] Unittest: Fix warning Change-Id: Ie78646d82786ad8836f289ba53382dad2d51d3f5 Reviewed-by: Nikolai Kosjar --- tests/unit/unittest/gtest-creator-printing.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h index 2a43f7d1a13..e26809ca519 100644 --- a/tests/unit/unittest/gtest-creator-printing.h +++ b/tests/unit/unittest/gtest-creator-printing.h @@ -81,7 +81,7 @@ std::ostream &operator<<(std::ostream &out, const HeaderPath &headerPath); namespace Utils { class LineColumn; class SmallStringView; -class Link; +struct Link; std::ostream &operator<<(std::ostream &out, const LineColumn &lineColumn); std::ostream &operator<<(std::ostream &out, const Utils::Language &language); From 44ddca544caa61f290d502fdf62f5bdbaf2b4f34 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 22 Oct 2019 17:25:33 +0200 Subject: [PATCH 30/57] Fix focusing of already open output pane from separate window If the focus is in a separate window and the shortcut for an already open output pane is triggered, we should set the focus there and activate the window, not close the output pane. Fixes: QTCREATORBUG-20083 Change-Id: Ia9f9fbe137c9ac1ad3e9d148cc410ca093275916 Reviewed-by: Christian Stenger --- src/plugins/coreplugin/outputpanemanager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/outputpanemanager.cpp b/src/plugins/coreplugin/outputpanemanager.cpp index 31af49521fa..00201293827 100644 --- a/src/plugins/coreplugin/outputpanemanager.cpp +++ b/src/plugins/coreplugin/outputpanemanager.cpp @@ -513,7 +513,8 @@ void OutputPaneManager::shortcutTriggered(int idx) // then just give it focus. int current = currentIndex(); if (OutputPanePlaceHolder::isCurrentVisible() && current == idx) { - if (!outputPane->hasFocus() && outputPane->canFocus()) { + if ((!m_outputWidgetPane->isActiveWindow() || !outputPane->hasFocus()) + && outputPane->canFocus()) { outputPane->setFocus(); ICore::raiseWindow(m_outputWidgetPane); } else { From 1fe204565a681d8882475327647f127f70509523 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 23 Oct 2019 16:02:56 +0300 Subject: [PATCH 31/57] QmlDesigner: Add support for move gadget to 3D edit view MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This proof-of-concept move gadget is based on the move gadget in studio example of QtQuick3D. Change-Id: I1b596443a3e99c16ed214bc464c5367a0f7aa503 Fixes: QDS-1125 Reviewed-by: Mahmoud Badri Reviewed-by: Thomas Hartmann Reviewed-by: Pasi Keränen --- .../qml/qmlpuppet/mockfiles/Arrow.qml | 126 +++++++++ .../qmlpuppet/mockfiles/AutoScaleHelper.qml | 85 ++++++ .../qml/qmlpuppet/mockfiles/EditView3D.qml | 94 +++++-- .../qml/qmlpuppet/mockfiles/MoveGizmo.qml | 79 ++++++ .../qml/qmlpuppet/mockfiles/meshes/Arrow.mesh | Bin 0 -> 6356 bytes .../qml2puppet/editor3d/editor3d.pri | 7 +- .../qml2puppet/editor3d/mousearea3d.cpp | 251 ++++++++++++++++++ .../qml2puppet/editor3d/mousearea3d.h | 125 +++++++++ .../qt5informationnodeinstanceserver.cpp | 32 ++- .../qt5informationnodeinstanceserver.h | 3 +- share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc | 4 + src/tools/qml2puppet/CMakeLists.txt | 1 + src/tools/qml2puppet/qml2puppet.qbs | 2 + 13 files changed, 782 insertions(+), 27 deletions(-) create mode 100644 share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml create mode 100644 share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml create mode 100644 share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml create mode 100644 share/qtcreator/qml/qmlpuppet/mockfiles/meshes/Arrow.mesh create mode 100644 share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp create mode 100644 share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml new file mode 100644 index 00000000000..7c9ef095897 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick3D 1.0 +import MouseArea3D 1.0 + +Model { + id: arrow + rotationOrder: Node.XYZr + source: "meshes/Arrow.mesh" + + property View3D view3D + property alias color: material.emissiveColor + property Node targetNode: null + + readonly property bool hovering: mouseAreaYZ.hovering || mouseAreaXZ.hovering + + property var _pointerPosPressed + property var _targetStartPos + + signal positionCommit() + + materials: DefaultMaterial { + id: material + emissiveColor: mouseAreaFront.hovering ? "white" : Qt.rgba(1.0, 0.0, 0.0, 1.0) + lighting: DefaultMaterial.NoLighting + } + + function handlePressed(mouseArea, pointerPosition) + { + if (!targetNode) + return; + + var maskedPosition = Qt.vector3d(pointerPosition.x, 0, 0); + _pointerPosPressed = mouseArea.mapPositionToScene(maskedPosition); + var sp = targetNode.positionInScene; + _targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z); + } + + function posInParent(mouseArea, pointerPosition) + { + var maskedPosition = Qt.vector3d(pointerPosition.x, 0, 0); + var scenePointerPos = mouseArea.mapPositionToScene(maskedPosition); + var sceneRelativeDistance = Qt.vector3d( + scenePointerPos.x - _pointerPosPressed.x, + scenePointerPos.y - _pointerPosPressed.y, + scenePointerPos.z - _pointerPosPressed.z); + + var newScenePos = Qt.vector3d( + _targetStartPos.x + sceneRelativeDistance.x, + _targetStartPos.y + sceneRelativeDistance.y, + _targetStartPos.z + sceneRelativeDistance.z); + + return targetNode.parent.mapPositionFromScene(newScenePos); + } + + function handleDragged(mouseArea, pointerPosition) + { + if (!targetNode) + return; + + targetNode.position = posInParent(mouseArea, pointerPosition); + } + + function handleReleased(mouseArea, pointerPosition) + { + if (!targetNode) + return; + + targetNode.position = posInParent(mouseArea, pointerPosition); + arrow.positionCommit(); + } + + MouseArea3D { + id: mouseAreaYZ + view3D: arrow.view3D + x: 0 + y: -1.5 + width: 12 + height: 3 + rotation: Qt.vector3d(0, 90, 0) + grabsMouse: targetNode + onPressed: arrow.handlePressed(mouseAreaYZ, pointerPosition) + onDragged: arrow.handleDragged(mouseAreaYZ, pointerPosition) + onReleased: arrow.handleReleased(mouseAreaYZ, pointerPosition) + } + + MouseArea3D { + id: mouseAreaXZ + view3D: arrow.view3D + x: 0 + y: -1.5 + width: 12 + height: 3 + rotation: Qt.vector3d(90, 90, 0) + grabsMouse: targetNode + onPressed: arrow.handlePressed(mouseAreaXZ, pointerPosition) + onDragged: arrow.handleDragged(mouseAreaXZ, pointerPosition) + onReleased: arrow.handleReleased(mouseAreaXZ, pointerPosition) + } + +} + diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml new file mode 100644 index 00000000000..c8d21604d3b --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick3D 1.0 +import MouseArea3D 1.0 + +Node { + id: overlayNode + + property View3D view3D + property Node target: parent + property bool autoScale: true + + // Read-only + property real relativeScale: 1 + + onGlobalTransformChanged: updateScale() + onAutoScaleChanged: updateScale() + Connections { + target: view3D.camera + onGlobalTransformChanged: updateScale() + } + + Connections { + target: window + onFirstFrameReady: updateScale() + } + + function getScale(baseScale) + { + return Qt.vector3d(baseScale.x * relativeScale, baseScale.y * relativeScale, + baseScale.z * relativeScale); + } + + function updateScale() + { + if (!autoScale) { + target.scale = Qt.vector3d(1, 1, 1); + } else { + // Calculate the distance independent scale by first mapping the targets position to + // the view. We then measure up a distance on the view (100px) that we use as an + // "anchor" distance. Map the two positions back to the target node, and measure the + // distance between them now, in the 3D scene. The difference of the two distances, + // view and scene, will tell us what the distance independent scale should be. + var posInView1 = view3D.mapFrom3DScene(positionInScene); + var posInView2 = Qt.vector3d(posInView1.x + 100, posInView1.y, posInView1.z); + + var rayPos1 = view3D.mapTo3DScene(Qt.vector3d(posInView2.x, posInView2.y, 0)); + var rayPos2 = view3D.mapTo3DScene(Qt.vector3d(posInView2.x, posInView2.y, 10)); + + var planeNormal = view3D.camera.forward; + var rayHitPos = helper.rayIntersectsPlane(rayPos1, rayPos2, positionInScene, + planeNormal); + relativeScale = positionInScene.minus(rayHitPos).length() / 100; + } + } + + MouseArea3D { + id: helper + view3D: overlayNode.view3D + } +} diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml index b9849d484c8..b0ec597cba1 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml @@ -42,7 +42,46 @@ Window { property alias showEditLight: editLightCheckbox.checked property alias usePerspective: usePerspectiveCheckbox.checked + property Node selectedNode: null + signal objectClicked(var object) + signal commitObjectPosition(var object) + + Node { + id: overlayScene + + Camera { + id: overlayCamera + projectionMode: usePerspectiveCheckbox.checked ? Camera.Perspective + : Camera.Orthographic + clipFar: editCamera.clipFar + position: editCamera.position + rotation: editCamera.rotation + } + + MoveGizmo { + id: moveGizmo + scale: autoScale.getScale(Qt.vector3d(5, 5, 5)) + highlightOnHover: true + targetNode: viewWindow.selectedNode + position: viewWindow.selectedNode ? viewWindow.selectedNode.positionInScene + : Qt.vector3d(0, 0, 0) + rotation: globalControl.checked || !viewWindow.selectedNode + ? Qt.vector3d(0, 0, 0) + : viewWindow.selectedNode.rotationInScene + + visible: selectedNode + view3D: overlayView + + onPositionCommit: viewWindow.commitObjectPosition(selectedNode) + } + + AutoScaleHelper { + id: autoScale + view3D: overlayView + position: moveGizmo.positionInScene + } + } Rectangle { id: sceneBg @@ -55,41 +94,47 @@ Window { var pickResult = editView.pick(eventPoint.scenePosition.x, eventPoint.scenePosition.y); viewWindow.objectClicked(pickResult.objectHit); + selectedNode = pickResult.objectHit; // TODO selection needs to come from studio } } View3D { id: editView anchors.fill: parent - enableWireframeMode: true camera: editCamera - AxisHelper { - id: axisGrid - enableXZGrid: true - enableAxisLines: false - } + Node { + id: mainSceneHelpers - PointLight { - id: pointLight - visible: showEditLight - position: editCamera.position - } + AxisHelper { + id: axisGrid + enableXZGrid: true + enableAxisLines: false + } - Camera { - id: editCamera - y: 200 - z: -300 - clipFar: 100000 - projectionMode: usePerspective ? Camera.Perspective : Camera.Orthographic - } + PointLight { + id: pointLight + visible: showEditLight + position: editCamera.position + } - Component.onCompleted: { - pointLight.setParentItem(editView.scene); - editCamera.setParentItem(editView.scene); + Camera { + id: editCamera + y: 200 + z: -300 + clipFar: 100000 + projectionMode: usePerspective ? Camera.Perspective : Camera.Orthographic + } } } + View3D { + id: overlayView + anchors.fill: parent + camera: overlayCamera + scene: overlayScene + } + WasdController { id: cameraControl controlledObject: editView.camera @@ -121,6 +166,13 @@ Window { text: qsTr("Use Perspective Projection") onCheckedChanged: cameraControl.forceActiveFocus() } + + CheckBox { + id: globalControl + checked: true + text: qsTr("Use global orientation") + onCheckedChanged: cameraControl.forceActiveFocus() + } } Text { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml new file mode 100644 index 00000000000..62a4e9e7c73 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick3D 1.0 + +Node { + id: arrows + + property View3D view3D + property bool highlightOnHover: false + property Node targetNode: null + + scale: Qt.vector3d(5, 5, 5) + + property alias arrowX: arrowX + property alias arrowY: arrowY + property alias arrowZ: arrowZ + + signal positionCommit() + + Arrow { + id: arrowX + objectName: "Arrow X" + rotation: Qt.vector3d(0, -90, 0) + targetNode: arrows.targetNode + color: highlightOnHover && hovering ? Qt.lighter(Qt.rgba(1, 0, 0, 1)) + : Qt.rgba(1, 0, 0, 1) + view3D: arrows.view3D + + onPositionCommit: arrows.positionCommit() + } + + Arrow { + id: arrowY + objectName: "Arrow Y" + rotation: Qt.vector3d(90, 0, 0) + targetNode: arrows.targetNode + color: highlightOnHover && hovering ? Qt.lighter(Qt.rgba(0, 0, 1, 1)) + : Qt.rgba(0, 0, 1, 1) + view3D: arrows.view3D + + onPositionCommit: arrows.positionCommit() + } + + Arrow { + id: arrowZ + objectName: "Arrow Z" + rotation: Qt.vector3d(0, 180, 0) + targetNode: arrows.targetNode + color: highlightOnHover && hovering ? Qt.lighter(Qt.rgba(0, 0.6, 0, 1)) + : Qt.rgba(0, 0.6, 0, 1) + view3D: arrows.view3D + + onPositionCommit: arrows.positionCommit() + } +} diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/Arrow.mesh b/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/Arrow.mesh new file mode 100644 index 0000000000000000000000000000000000000000..f872b5e008ed13e38022a3605fa198ed278010e0 GIT binary patch literal 6356 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 literal 0 HcmV?d00001 diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri index 7b86f8bc820..a052b7285c9 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri @@ -1,2 +1,5 @@ -HEADERS += $$PWD/cameracontrolhelper.h -SOURCES += $$PWD/cameracontrolhelper.cpp +HEADERS += $$PWD/cameracontrolhelper.h \ + $$PWD/mousearea3d.h + +SOURCES += $$PWD/cameracontrolhelper.cpp \ + $$PWD/mousearea3d.cpp diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp new file mode 100644 index 00000000000..e3ec5c704bb --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp @@ -0,0 +1,251 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#ifdef QUICK3D_MODULE + +#include "mousearea3d.h" + +#include +#include + +namespace QmlDesigner { +namespace Internal { + +MouseArea3D *MouseArea3D::s_mouseGrab = nullptr; + +MouseArea3D::MouseArea3D(QQuick3DNode *parent) + : QQuick3DNode(parent) +{ +} + +QQuick3DViewport *MouseArea3D::view3D() const +{ + return m_view3D; +} + +bool MouseArea3D::hovering() const +{ + return m_hovering; +} + +bool MouseArea3D::dragging() const +{ + return m_dragging; +} + +bool MouseArea3D::grabsMouse() const +{ + return m_grabsMouse; +} + +qreal MouseArea3D::x() const +{ + return m_x; +} + +qreal MouseArea3D::y() const +{ + return m_y; +} + +qreal MouseArea3D::width() const +{ + return m_width; +} + +qreal MouseArea3D::height() const +{ + return m_height; +} + +void MouseArea3D::setView3D(QQuick3DViewport *view3D) +{ + if (m_view3D == view3D) + return; + + m_view3D = view3D; + emit view3DChanged(); +} + +void MouseArea3D::setGrabsMouse(bool grabsMouse) +{ + if (m_grabsMouse == grabsMouse) + return; + + m_grabsMouse = grabsMouse; + emit grabsMouseChanged(grabsMouse); +} + +void MouseArea3D::setX(qreal x) +{ + if (qFuzzyCompare(m_x, x)) + return; + + m_x = x; + emit xChanged(x); +} + +void MouseArea3D::setY(qreal y) +{ + if (qFuzzyCompare(m_y, y)) + return; + + m_y = y; + emit yChanged(y); +} + +void MouseArea3D::setWidth(qreal width) +{ + if (qFuzzyCompare(m_width, width)) + return; + + m_width = width; + emit widthChanged(width); +} + +void MouseArea3D::setHeight(qreal height) +{ + if (qFuzzyCompare(m_height, height)) + return; + + m_height = height; + emit heightChanged(height); +} + +void MouseArea3D::componentComplete() +{ + if (!m_view3D) { + qmlDebug(this) << "property 'view3D' is not set!"; + return; + } + m_view3D->setAcceptedMouseButtons(Qt::LeftButton); + m_view3D->setAcceptHoverEvents(true); + m_view3D->setAcceptTouchEvents(false); + m_view3D->installEventFilter(this); +} + +QVector3D MouseArea3D::rayIntersectsPlane(const QVector3D &rayPos0, + const QVector3D &rayPos1, + const QVector3D &planePos, + const QVector3D &planeNormal) const +{ + QVector3D rayDirection = rayPos1 - rayPos0; + QVector3D rayPos0RelativeToPlane = rayPos0 - planePos; + + float dotPlaneRayDirection = QVector3D::dotProduct(planeNormal, rayDirection); + float dotPlaneRayPos0 = -QVector3D::dotProduct(planeNormal, rayPos0RelativeToPlane); + + if (qFuzzyIsNull(dotPlaneRayDirection)) { + // The ray is is parallel to the plane. Note that if dotLinePos0 == 0, it + // additionally means that the line lies in plane as well. In any case, we + // signal that we cannot find a single intersection point. + return QVector3D(0, 0, -1); + } + + // Since we work with a ray (that has a start), distanceFromLinePos0ToPlane + // must be above 0. If it was a line segment (with an end), it also need to be less than 1. + // (Note: a third option would be a "line", which is different from a ray or segment in that + // it has neither a start, nor an end). Then we wouldn't need to check the distance at all. + // But that would also mean that the line could intersect the plane behind the camera, if + // the line were directed away from the plane when looking forward. + float distanceFromRayPos0ToPlane = dotPlaneRayPos0 / dotPlaneRayDirection; + if (distanceFromRayPos0ToPlane <= 0) + return QVector3D(0, 0, -1); + return rayPos0 + distanceFromRayPos0ToPlane * rayDirection; +} + +QVector3D MouseArea3D::getMousePosInPlane(const QPointF &mousePosInView) const +{ + const QVector3D mousePos1(float(mousePosInView.x()), float(mousePosInView.y()), 0); + const QVector3D mousePos2(float(mousePosInView.x()), float(mousePosInView.y()), 1); + const QVector3D rayPos0 = m_view3D->mapTo3DScene(mousePos1); + const QVector3D rayPos1 = m_view3D->mapTo3DScene(mousePos2); + const QVector3D globalPlanePosition = mapPositionToScene(QVector3D(0, 0, 0)); + const QVector3D intersectGlobalPos = rayIntersectsPlane(rayPos0, rayPos1, + globalPlanePosition, forward()); + if (qFuzzyCompare(intersectGlobalPos.z(), -1)) + return intersectGlobalPos; + + return mapPositionFromScene(intersectGlobalPos); +} + +bool MouseArea3D::eventFilter(QObject *, QEvent *event) +{ + switch (event->type()) { + case QEvent::HoverMove: { + if (m_grabsMouse && s_mouseGrab && s_mouseGrab != this) + break; + + auto const mouseEvent = static_cast(event); + const QVector3D mousePosInPlane = getMousePosInPlane(mouseEvent->pos()); + if (qFuzzyCompare(mousePosInPlane.z(), -1)) + break; + + const bool mouseOnTopOfMouseArea = + mousePosInPlane.x() >= float(m_x) && + mousePosInPlane.x() <= float(m_x + m_width) && + mousePosInPlane.y() >= float(m_y) && + mousePosInPlane.y() <= float(m_y + m_height); + + const bool buttonPressed = QGuiApplication::mouseButtons().testFlag(Qt::LeftButton); + + // The filter will detect a mouse press on the view, but not a mouse release, since the + // former is not accepted by the view, which means that the release will end up being + // sent elsewhere. So we need this extra logic inside HoverMove, rather than in + // MouseButtonRelease, which would otherwise be more elegant. + + if (m_hovering != mouseOnTopOfMouseArea) { + m_hovering = mouseOnTopOfMouseArea; + emit hoveringChanged(); + } + + if (!m_dragging && m_hovering && buttonPressed) { + m_dragging = true; + emit pressed(mousePosInPlane); + emit draggingChanged(); + } else if (m_dragging && !buttonPressed) { + m_dragging = false; + emit released(mousePosInPlane); + emit draggingChanged(); + } + + if (m_grabsMouse) + s_mouseGrab = m_hovering || m_dragging ? this : nullptr; + + if (m_dragging) + emit dragged(mousePosInPlane); + + break; } + default: + break; + } + + return false; +} + +} +} + +#endif // QUICK3D_MODULE diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h new file mode 100644 index 00000000000..b42b438b473 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#ifdef QUICK3D_MODULE + +#include +#include + +#include +#include +#include + +namespace QmlDesigner { +namespace Internal { + +class MouseArea3D : public QQuick3DNode +{ + Q_OBJECT + Q_PROPERTY(QQuick3DViewport *view3D READ view3D WRITE setView3D NOTIFY view3DChanged) + Q_PROPERTY(bool grabsMouse READ grabsMouse WRITE setGrabsMouse NOTIFY grabsMouseChanged) + Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged) + Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged) + Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY widthChanged) + Q_PROPERTY(qreal height READ height WRITE setHeight NOTIFY heightChanged) + Q_PROPERTY(bool hovering READ hovering NOTIFY hoveringChanged) + Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged) + + Q_INTERFACES(QQmlParserStatus) + +public: + MouseArea3D(QQuick3DNode *parent = nullptr); + + QQuick3DViewport *view3D() const; + + qreal x() const; + qreal y() const; + qreal width() const; + qreal height() const; + + bool hovering() const; + bool dragging() const; + bool grabsMouse() const; + +public slots: + void setView3D(QQuick3DViewport *view3D); + void setGrabsMouse(bool grabsMouse); + + void setX(qreal x); + void setY(qreal y); + void setWidth(qreal width); + void setHeight(qreal height); + + Q_INVOKABLE QVector3D rayIntersectsPlane(const QVector3D &rayPos0, + const QVector3D &rayPos1, + const QVector3D &planePos, + const QVector3D &planeNormal) const; + +signals: + void view3DChanged(); + + void xChanged(qreal x); + void yChanged(qreal y); + void widthChanged(qreal width); + void heightChanged(qreal height); + + void hoveringChanged(); + void draggingChanged(); + void pressed(const QVector3D &pointerPosition); + void released(const QVector3D &pointerPosition); + void dragged(const QVector3D &pointerPosition); + void grabsMouseChanged(bool grabsMouse); + +protected: + void classBegin() override {} + void componentComplete() override; + bool eventFilter(QObject *obj, QEvent *event) override; + +private: + Q_DISABLE_COPY(MouseArea3D) + QQuick3DViewport *m_view3D = nullptr; + + qreal m_x; + qreal m_y; + qreal m_width; + qreal m_height; + + bool m_hovering = false; + bool m_dragging = false; + + QVector3D getMousePosInPlane(const QPointF &mousePosInView) const; + + static MouseArea3D *s_mouseGrab; + bool m_grabsMouse; +}; + +} +} + +QML_DECLARE_TYPE(QmlDesigner::Internal::MouseArea3D) + +#endif // QUICK3D_MODULE diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 685136cb2d4..0cb95c98d9c 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -59,6 +59,7 @@ #include "dummycontextobject.h" #include "../editor3d/cameracontrolhelper.h" +#include "../editor3d/mousearea3d.h" #include @@ -77,9 +78,13 @@ static QVariant objectToVariant(QObject *object) QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine) { - QmlDesigner::Internal::CameraControlHelper *helper = new QmlDesigner::Internal::CameraControlHelper(); + auto helper = new QmlDesigner::Internal::CameraControlHelper(); engine->rootContext()->setContextProperty("designStudioNativeCameraControlHelper", helper); +#ifdef QUICK3D_MODULE + qmlRegisterType("MouseArea3D", 1, 0, "MouseArea3D"); +#endif + QQmlComponent component(engine, QUrl("qrc:/qtquickplugin/mockfiles/EditView3D.qml")); QWindow *window = qobject_cast(component.create()); @@ -90,6 +95,8 @@ QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine) } QObject::connect(window, SIGNAL(objectClicked(QVariant)), this, SLOT(objectClicked(QVariant))); + QObject::connect(window, SIGNAL(commitObjectPosition(QVariant)), + this, SLOT(handleObjectPositionCommit(QVariant))); //For macOS we have to use the 4.1 core profile QSurfaceFormat surfaceFormat = window->requestedFormat(); @@ -101,10 +108,29 @@ QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine) return window; } -// an object is clicked in the 3D edit view +// an object is clicked in the 3D edit view. Null object indicates selection clearing. void Qt5InformationNodeInstanceServer::objectClicked(const QVariant &object) { - selectInstance(instanceForObject(object.value())); + auto obj = object.value(); + ServerNodeInstance instance; + if (obj) + instance = instanceForObject(obj); + selectInstance(instance); +} + +void Qt5InformationNodeInstanceServer::handleObjectPositionCommit(const QVariant &object) +{ + QObject *obj = object.value(); + if (obj) { + ServerNodeInstance instance = instanceForObject(obj); + QVector modifiedpropertyList; + InstancePropertyValueTriple propTriple; + propTriple.instance = instance; + propTriple.propertyName = "position"; + propTriple.propertyValue = obj->property(propTriple.propertyName.constData()); + modifiedpropertyList.append(propTriple); + nodeInstanceClient()->valuesModified(createValuesModifiedCommand(modifiedpropertyList)); + } } Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) : diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index 2e39339583a..243b3339049 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -44,8 +44,9 @@ public: void removeSharedMemory(const RemoveSharedMemoryCommand &command) override; void changeSelection(const ChangeSelectionCommand &command) override; -public slots: +private slots: void objectClicked(const QVariant &object); + void handleObjectPositionCommit(const QVariant &object); protected: void collectItemChangesAndSendChangeCommands() override; diff --git a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc index 8354e475f17..001591a96d5 100644 --- a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc +++ b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc @@ -8,5 +8,9 @@ mockfiles/GenericBackend.qml mockfiles/Dialog.qml mockfiles/EditView3D.qml + mockfiles/Arrow.qml + mockfiles/AutoScaleHelper.qml + mockfiles/MoveGizmo.qml + mockfiles/meshes/Arrow.mesh diff --git a/src/tools/qml2puppet/CMakeLists.txt b/src/tools/qml2puppet/CMakeLists.txt index 105b0a63f0b..d2f43adc1b3 100644 --- a/src/tools/qml2puppet/CMakeLists.txt +++ b/src/tools/qml2puppet/CMakeLists.txt @@ -108,6 +108,7 @@ extend_qtc_executable(qml2puppet SOURCES_PREFIX "${SRCDIR}/qml2puppet/editor3d" SOURCES cameracontrolhelper.cpp cameracontrolhelper.h + mousearea3d.cpp mousearea3d.h ) extend_qtc_executable(qml2puppet diff --git a/src/tools/qml2puppet/qml2puppet.qbs b/src/tools/qml2puppet/qml2puppet.qbs index 995c29eac04..5bf57a534c7 100644 --- a/src/tools/qml2puppet/qml2puppet.qbs +++ b/src/tools/qml2puppet/qml2puppet.qbs @@ -197,6 +197,8 @@ QtcTool { "instances/servernodeinstance.h", "editor3d/cameracontrolhelper.cpp", "editor3d/cameracontrolhelper.h", + "editor3d/mousearea3d.cpp", + "editor3d/mousearea3d.h", "qml2puppetmain.cpp", ] } From b83b93fb7fffe21a00ff99134669bc29f2d0ab70 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Thu, 24 Oct 2019 15:17:47 +0300 Subject: [PATCH 32/57] Make 3D objects pickable Mark 3D objects implicitly pickable upon initialization so that they receive mouse clicks without having to declare the pickable property in qml. Task-number: QDS-1124 Change-Id: Ib8ec5415097c1a9bf57b8965a3fca0c3665f3732 Reviewed-by: Thomas Hartmann --- .../instances/quick3dnodeinstance.cpp | 17 +++++++++++++++++ .../qml2puppet/instances/quick3dnodeinstance.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp index 29c3ab3f299..27a52e48a40 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp @@ -52,6 +52,23 @@ Quick3DNodeInstance::~Quick3DNodeInstance() { } +void Quick3DNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNodeInstance, + InstanceContainer::NodeFlags flags) +{ + ObjectNodeInstance::initialize(objectNodeInstance, flags); + +#ifdef QUICK3D_MODULE + if (quick3DNode()) { + QQuick3DObject::Type nodeType = quick3DNode()->type(); + if (nodeType == QQuick3DObject::Camera || nodeType == QQuick3DObject::Light + || nodeType == QQuick3DObject::Model || nodeType == QQuick3DObject::Image + || nodeType == QQuick3DObject::Text) { + setPropertyVariant("pickable", true); // allow 3D objects to receive mouse clicks + } + } +#endif +} + Qt5NodeInstanceServer *Quick3DNodeInstance::qt5NodeInstanceServer() const { return qobject_cast(nodeInstanceServer()); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h index 6bfc2a02a19..96c44c4d525 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h @@ -44,6 +44,8 @@ public: ~Quick3DNodeInstance() override; static Pointer create(QObject *objectToBeWrapped); void setHideInEditor(bool b) override; + void initialize(const ObjectNodeInstance::Pointer &objectNodeInstance, + InstanceContainer::NodeFlags flags) override; protected: explicit Quick3DNodeInstance(QObject *node); From 999564d3935073ccc412271666c25327c72130e8 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Wed, 23 Oct 2019 15:31:30 +0200 Subject: [PATCH 33/57] Doc: Describe using Qt Design Viewer For running Qt Quick UI projects (.qmlproject) in web browsers. Change-Id: Ied9b971755ccef9f94e9e0ffb578d3ecbd0ef6c0 Reviewed-by: Thomas Hartmann --- doc/config/macros.qdocconf | 1 + doc/images/qt-design-viewer.png | Bin 0 -> 46254 bytes .../creator-projects-building.qdoc | 2 +- doc/src/qtcreator-toc.qdoc | 1 + doc/src/qtquick/qt-design-viewer.qdoc | 72 ++++++++++++++++++ .../qtquick/qtquick-live-preview-devices.qdoc | 6 +- doc/src/qtquick/qtquick-live-preview.qdoc | 13 ++++ 7 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 doc/images/qt-design-viewer.png create mode 100644 doc/src/qtquick/qt-design-viewer.qdoc diff --git a/doc/config/macros.qdocconf b/doc/config/macros.qdocconf index a6817d36426..c71ddf7fa2a 100644 --- a/doc/config/macros.qdocconf +++ b/doc/config/macros.qdocconf @@ -21,6 +21,7 @@ macro.QC = "$IDE_DISPLAY_NAME" macro.QCE = "$IDE_DISPLAY_NAME Enterprise" macro.QD = "Qt Designer" macro.QDS = "Qt Design Studio" +macro.QDV = "Qt Design Viewer" macro.QL = "Qt Linguist" macro.QMLD = "Qt Quick Designer" macro.QQV = "Qt QML Viewer" diff --git a/doc/images/qt-design-viewer.png b/doc/images/qt-design-viewer.png new file mode 100644 index 0000000000000000000000000000000000000000..1c4916036be1bed81526185be773e52f498a5de3 GIT binary patch literal 46254 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 XUuAFGdbd@g9;D3E)z4*}Q$iB}_{*Zk literal 0 HcmV?d00001 diff --git a/doc/src/projects/creator-only/creator-projects-building.qdoc b/doc/src/projects/creator-only/creator-projects-building.qdoc index 14f97704563..c87557dc699 100644 --- a/doc/src/projects/creator-only/creator-projects-building.qdoc +++ b/doc/src/projects/creator-only/creator-projects-building.qdoc @@ -31,7 +31,7 @@ /*! \contentspage index.html - \previouspage creator-live-preview-devices.html + \previouspage qt-design-viewer.html \page creator-building-targets.html \nextpage creator-running-targets.html diff --git a/doc/src/qtcreator-toc.qdoc b/doc/src/qtcreator-toc.qdoc index 7774af49512..f0bd3f9e02a 100644 --- a/doc/src/qtcreator-toc.qdoc +++ b/doc/src/qtcreator-toc.qdoc @@ -160,6 +160,7 @@ \list \li \l{Previewing on Desktop} \li \l{Previewing on Devices} + \li \l{Previewing in Browsers} \endlist \li \l{Building for Multiple Platforms} \li \l{Running on Multiple Platforms} diff --git a/doc/src/qtquick/qt-design-viewer.qdoc b/doc/src/qtquick/qt-design-viewer.qdoc new file mode 100644 index 00000000000..2c63c05baf4 --- /dev/null +++ b/doc/src/qtquick/qt-design-viewer.qdoc @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Studio documentation. +** +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** +****************************************************************************/ + +/*! + \contentspage {Qt Creator} + \previouspage creator-live-preview-devices.html + \page qt-design-viewer.html + \if defined(qtdesignstudio) + \nextpage studio-advanced.html + \else + \nextpage creator-building-targets.html + \endif + + \title Previewing in Browsers + + \image qt-design-viewer.png + + \QDV is a QML viewer that runs in your web browser. This means that you can + run applications in most widely-used web browsers, such as Apple Safari, + Google Chrome, Microsoft Edge, and Mozilla Firefox, on the desktop and on + mobile devices. + + The startup and compilation time depend on your browser and configuration. + However, the actual performance of the application once started is + indistinguishable from the same application running on the desktop. + + \if defined(qtdesignstudio) + To create a resource file out of your project, select \uicontrol Tools > + \uicontrol {Generate Resource File} in \QC. Then upload the package into + \QDV. + \else + You can run \l{Creating Qt Quick UI Projects}{Qt Quick UI projects}, which + have a .qmlproject file that define the main QML file and the import paths. + Compress the project folder into a ZIP file that you upload to \QDV. + \endif + + The loaded applications remain locally in your browser. No data is uploaded + into the cloud. + + To preview an application in a web browser: + + \list + \li In the browser, open \l{http://qt-webassembly.io/designviewer/} + {\QDV}. + \li Drag and drop your application package to \QDV, or click the load + icon to browse for your file. + \endlist + + Your application is compiled and run on \QDV. +*/ diff --git a/doc/src/qtquick/qtquick-live-preview-devices.qdoc b/doc/src/qtquick/qtquick-live-preview-devices.qdoc index d37b84075a1..4686ef485b0 100644 --- a/doc/src/qtquick/qtquick-live-preview-devices.qdoc +++ b/doc/src/qtquick/qtquick-live-preview-devices.qdoc @@ -27,11 +27,7 @@ \contentspage {Qt Creator} \previouspage creator-live-preview-desktop.html \page creator-live-preview-devices.html - \if defined(qtdesignstudio) - \nextpage studio-advanced.html - \else - \nextpage creator-building-targets.html - \endif + \nextpage qt-design-viewer.html \title Previewing on Devices diff --git a/doc/src/qtquick/qtquick-live-preview.qdoc b/doc/src/qtquick/qtquick-live-preview.qdoc index 95b01b9fe2a..9145c2826a0 100644 --- a/doc/src/qtquick/qtquick-live-preview.qdoc +++ b/doc/src/qtquick/qtquick-live-preview.qdoc @@ -40,6 +40,15 @@ devices. The changes you make to the UI are instantly visible to you in the preview. + In addition, you can use \QDV to run + \if defined(qtcreator) + \l{Creating Qt Quick UI Projects}{Qt Quick UI projects} + \else + applications + \endif + in most widely-used web browsers on the desktop and in mobile devices This + enables you to easily share your designs with reviewers who don't have \QC. + \if defined(qtcreator) \image qtcreator-live-preview.png \else @@ -62,5 +71,9 @@ devices is set up automatically. You only need to connect your devices to your system. \endif + \li \l{Previewing in Browsers} + + You can open \l{http://qt-webassembly.io/designviewer/}{\QDV} + in a browser and load applications to it. \endlist */ From 362d65301d58eb9bcaec4909c876b1590847ebab Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Mon, 21 Oct 2019 15:52:06 +0200 Subject: [PATCH 34/57] Doc: Update info about the binding editor Change-Id: I78e8a1c090b01f8062109928305f391b1b8b49be Reviewed-by: Thomas Hartmann --- doc/images/icons/action-icon-binding.png | Bin 0 -> 417 bytes doc/images/icons/action-icon.png | Bin 0 -> 273 bytes doc/images/qmldesigner-binding-editor.png | Bin 4189 -> 5228 bytes doc/images/qmldesigner-set-expression.png | Bin 4213 -> 10970 bytes doc/src/qtquick/qtquick-components.qdoc | 19 +++++++++++++------ doc/src/qtquick/qtquick-properties.qdoc | 6 +++--- 6 files changed, 16 insertions(+), 9 deletions(-) create mode 100644 doc/images/icons/action-icon-binding.png create mode 100644 doc/images/icons/action-icon.png diff --git a/doc/images/icons/action-icon-binding.png b/doc/images/icons/action-icon-binding.png new file mode 100644 index 0000000000000000000000000000000000000000..34b2c6adda293993909461232ef7b5081555d89e GIT binary patch literal 417 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7I14-?iy0XBj({-ZRBb+K z1_s7pPZ!4!i{94DhTbxPBCHSeZ|ZC`FylOU=w53A7q=jfW{ZoXu8zqM<|(ZrZ6=OR z94tXk)Nicmj@{-G|?7ij#P@xA?v7`#Yc0ysF$e zL6I|sy^W@b(ocYOjUpP%T8$CVleej=SY5O#OYrIyjrp(koa$S#piO(O{rQ^p$CN%NuPih+Jf!!nTJR2Iet6`$ V9rpEC7#J8BJYD@<);T3K0RZF3v1m+n?AaD}f&~uB zyfZ{N{u{a6`H`3RScap@v$^iT{EvLy4R_d#Z?WyFl%4Jnv%aFdQOwWrmw}+0eaWdk z53B`ZKF(Kss2Xp Zvw1`FMvL>47#J8BJYD@<);T3K0RXeEW`_U( literal 0 HcmV?d00001 diff --git a/doc/images/qmldesigner-binding-editor.png b/doc/images/qmldesigner-binding-editor.png index 0fd07427b63e267e962c2d98ce7844b605db5e59..fc6650bc5bcc1b9b74e8305c91c5afa1d6857e49 100644 GIT binary patch literal 5228 zcmeAS@N?(olHy`uVBq!ia0y~yV2Wg5U=-kBVqjq4QT?XLz#wAm>EaktaqI2fzr`|N z6B|DMllS>}nrH5^nTlq9ZV8^#a!yXtz1<$)VQ_55^d+*7D{{&|nXwu11_xc&R~6t$ zP|y=Td{a$vp~>Tx9=4XdOU|lnR7}ZG3i@=F%UTSqW^3&bt zGt-Y`=9lMxf4A>XI=EBzs}^m z&U^RE!DRnu=Y8^Dy-fGBskuLQ=e>garzS?ft9!9|`SSNxpU()(-`~1x`SSeBbKC8T zSJ`~M(s{Ug{d@lGQ?(y1ZkQF!Uz2cmt8MM$?=@;Q#h*UNI@{VdZ~yZ)IPqoupC5gV zS4zL-TYh+O@=};h?UVKVZmUn(Z%F@g>&CWkcMGlyU;LZ+>sNL)!-CyECtuiU&%|(H zZH6L)1NT+|h6Sxr91ItnbXgcO6d4%qdi`i-0PA-=KMdu4&8fyUvyLX;qrUmFRlOg^!Wb&nFe<_?yGJ6u(tEDsMiC~WPb-TbH(o#S*zQX%$y)>%F8J_C^Cvp%#(ey9q4odYb9>jz z@osO9K7Zfv>uq!UZ_WGbe}>0bzuUjx&(N)oNxGWACJ59@9+J6l@D%z z-}9xLEjr@=>RlB#PEB4sd+T;C$yND@&D|+EhkN)1?WeE(Z<=m$ai%guNg(&~^%KRS zcl>?2pGUXmy?6PXpBF!;*M0i4s($yri=Pjznx+!A{Ey@`uk?GfGU_IN`F!Y@{Gwmw zbDkPUiw80$IJR&2dfj93`Ex$DU*E>>HT(7GN4(AT>R0aZf3C;Zyq@*^x=h{Q;PwBX z^?udAx8u!e=VWoIA8&kAb)q;JGLkuj_sQhbP&k{<`+XJz3ABByPqY zk4I)x-k+}O_%wIx{JAqvvnMe!yj|K`pB*p1$29()QAJttj)ExTzmwP7Z&R4pllHGm zkm17BGrL+l^`;2?>QHA`@Kkq?Psd;01(Tf^9KyE=Ffiz{FgS2CGF)(CVAz7not5!$ zJ|n}0wO_t}&xYr#c^nK4VoVGRS{cAuD+-M}3|JJbA->X11Tq^#e{)8EZ2W7lyfVz5nt; zcK&()W6MI$hDbP?Ztczse>TIWZco-3k#r6HNnZ+{P86%}c%?hrh+`vzTjrx5IeS_; z^Z%XV?^+tB%0FSv!(iJeVYZOW4{y%<-#_ubzcyHE-&SwY>8oY0yMH!aEHdMN+9q9@0oWfAx3WR&%+8GYE$yttQS>#1$TX(k`@`aGqzrN-@RL%8{55WI&MsP`t>x^ z^sdm=VXYH?9uf9$S^u!?kxin*(ya#BYeN4?@1JVoVASS+He)T%ichajoeujqTmMYJ zk7XwDcMW{xt_N>iYpSv_fi0>#D&q6x1mEXbM$;@(!*qRWcCg7a%~&2-^?vX7WxeMk zw`_QJHeU4Tr)Zn%1`~^@$D2jZKk70T`5d__{^{(eorevQW27fVcrdU1DYh3H-2KQ}1uj ziLa}AlfpCMn0xl837pMZQjrfoa&3OzpVMiZ_xG03v8{@ottJJU8t_!O_T9a*K?zYrGp;-6aAtbhSPV-*-m6 z?_x|B4yAEfgcdL3$WTmJuys}IL;0p%QV!i5%vx((k4as4*LdyE{-?KZ-?p}}crlap znV*DLqQla^(fc5BDcs`vaeGQ$UYe>MzAkom84ENQ8!VWn6PdJz@w3r|tQRj|X0B*$ z+^|b~{hm);48>|ZOM5u)y@D69a>l5U3hnD8|IF1yt=ut!RZ7K%0LCGcf4+ zN8LQM`u^4)m6NBvbyYmG7K%+$*&4v@IVoyItBR-Y6{kr{#Ih7UgSdC^XszbkSNQS4 zy>(S@^z}w?Z<0 zeMZ~y`xb`t_RhOg+kQAl_&cw)z=S9Z`{%6>C2oBZYjci1RJgXtLeH`=seGMjzeU|9 z1F!+gIrGqv@U93$&tn`Y))`DreXWrUXek*v{^5)G!=jyiA z{0k1Z`^os(gx{{df3Wis=fQ`a!jE_U(vEt%dGDpb9q*p3FOl%I6bt9OFDd@G+#%8(JTRYUob=c~4_Y!JeXTGm9city+pa%5u4X|NcGO zPG9ES(lO8$Y(63wzhKEc~j~;hwV+c9mtnZVO!h!8QBlk7x6Gd!`#Dx3>Gq+>yTh z_e0B+Vu>=9Gch;jCY?W29Qu3Hwe=ee>YuW=I%P;(>-TuY#2ASGZ3y~*+0&Qf>4YnX z)Xs4~w(k#@b;#zkdaC(QBdj{fuy)G+CAvQMe|%Yb$$Z~Cr})xco6d6wn=js^yzzzE z?vK89(l7N>e{l()yL#y4op+~OFBzh84lm7kc!vG;ncn>^x^oJRy~0ISU%z(enEB6~CHtq$eChRnYVMXp z!b>N${+;Dv5x%=bw*1X!iN9~+_wh}Wz9;=xPyO$qs4v#rX0D&;#=hfH&f$ye zpXy!Py1^uUhk4bGm`Ca9Qad}Q@BFB{!!2ruN%-YMkM66t#K)h_GUlp|tq!_z=a~8T zoRmFNZu*D(nZ9!8A#LgZ!R?Q+$h^Di zr{$wH>T^^+Z#EVWwyP8RJ>&2~Vbl5B*4M}=ME^*{hz3NxYk$zUrNCMZU;l>%Y@G zjy|`4``)}|!WF0g{M)YGe(|1rXM%`R5ck#%OY6CIE-$!xG1zfZ)Q#HbP5t5jT+Vwc zdS)qlPKxrFv_x!@%F0%if##>QGvTOBSqP~fJsZls{G)=c{5SB=F3HQOe1!0 zX|=VrCD9ioyHWPmp@0ACFoNl%UhcyiH)e=UQrW$$wYIjFkTW*Dj=EvJC5+p1QtaJB ztL=+CxIHJ`y?dzNZb7TcNj-c0J^olKfvpo%Zcf#GBQ0^oX;Mo0_6z^Z+tA}}_qNvL zeFHUPJ%hMWg6h|s9YJz=2SE+z9h;*# z7(!cwmtE*Q``DV@-K=y&BKzUIwz+HT*$#1Do@JWt=H__-nzq6z8arLf-4YL!|(`&rJE&hge*$;p8-DYbu zFWHl5ZXEUFot^_Xqr&4oAFhQSPL|ET;j4SaiNPcDq3`x}Qc|xg4(Bb~T5!0HS6fWy zcAu}G-0f>!rmc5DO7b4^-Y);TKJtE8{=X|fR~kLH`}!~A(c1ZTF)sh?!CM zETMY4;+wSF(G?G_e97~hYqg-2q2T70g4^F>YqPIyJuj=+@?7p-;ID7=kF~Ei&!|-CA*u5RA^S|!eCi$rR-{jp%!DXUa7Js)sySGiUZ1Y@QAHOig39ek< z#hzKs()ZQ6UQ}P{l<1W@^OVx`U9HjE?HVR*;)cI(i?t;)yP8s23+{BiEy!HH#+-V0kph2Qr@Ni1s@u>0|I<*n-5sW;Ak z+h(vaVx#ckm9sXeF4MEC|L9T}7gh1*hG8@>aK}AyJyRV^mK-jXm0cV`!#nD z-1;VY_1zuk+urx@)mCM_n#!KPKkvEo`YCGn>i+LMG^H%h+2BoD6!-PD(c5#*E z{<{|?iE;@rAEFiEAda=xFM!Sck0b3ha0}2BrdkE{CMf=w%f11 zv1`=_7yeRi?KBsUikS6qoyG+IJJ+t|a_qi&O>A1RMQv$u{K}l8uNVLPlTyUJTC7{F zYyHwRL0y&xv#lR~Nteakw!ibS?XFMu!xt}J>;@&Dw}`f>=v=M`tvVd=_$NfCdTBzw0M3+YDLNAUA)m%RpI4G`Nsa`b#U|d z#!W>YYl*VW6YKW}a5I+3{w=rL^X);g^WxcNxqA(-FKmnDw%+k=o&J~ibu0c!M(n95 z{BiwW__~;#Wp8gygyhi;v%RP3Ty$dau=@7)=a&=eah-LAH+Htk`tT%94Cny0kGuNR z-Xti4hMYh>Z=@kBaQpazFxF1_uFb8}#UK8+wlgr;U^V$5(|er_Noqwq?`SbNh=2b7 YeUhH4)7|?u3=9kmp00i_>zopr05@kKMgRZ+ literal 4189 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 XMODo?)O3J>fq}u()z4*}Q$iB}IZhWH diff --git a/doc/src/qtquick/qtquick-components.qdoc b/doc/src/qtquick/qtquick-components.qdoc index 9a82fbd44d7..d8327fd2f85 100644 --- a/doc/src/qtquick/qtquick-components.qdoc +++ b/doc/src/qtquick/qtquick-components.qdoc @@ -170,20 +170,27 @@ Property bindings are created implicitly in QML whenever a property is assigned a JavaScript expression. To set JavaScript expressions as values - of properties in the Design mode, select the \uicontrol Settings menu next to - a property, and then select \uicontrol {Set Binding}. + of properties in the Design mode, select the + \inlineimage icons/action-icon.png + (\uicontrol Actions) menu next to a property, and then select + \uicontrol {Set Binding}. \image qmldesigner-set-expression.png "Type properties context menu" - The \uicontrol {Binding Editor} supports code completion. Start typing a + In the \uicontrol {Binding Editor}, select an item and a property from + lists of available items and their properties. + + \image qmldesigner-binding-editor.png "Binding Editor" + + Alternatively, start typing a string and press \key Ctrl+Space to display a list of properties, IDs, and code snippets. When you enter a period (.) after a property name, a list of available values is displayed. Press \key Enter to accept the first suggestion in the list and to complete the code. - \image qmldesigner-binding-editor.png "Binding Editor" - - To remove bindings, select \uicontrol Reset in the context menu. + When a binding is set, the \uicontrol Actions menu icon changes to + \inlineimage icons/action-icon-binding + . To remove bindings, select \uicontrol Reset in the \uicontrol Actions menu. You can set bindings also in the \uicontrol Connections view. For more information, see \l {Adding Bindings Between Properties}. diff --git a/doc/src/qtquick/qtquick-properties.qdoc b/doc/src/qtquick/qtquick-properties.qdoc index add17138c4f..e7ce811e491 100644 --- a/doc/src/qtquick/qtquick-properties.qdoc +++ b/doc/src/qtquick/qtquick-properties.qdoc @@ -46,9 +46,9 @@ \uicontrol Properties pane, and enter the name of another QML type in the field. If you have specified properties for the item that are not supported for the new type, the type cannot be changed and an error message is - displayed. Select the \uicontrol Settings menu next to the property name, and - then select \uicontrol Reset to remove the property values before trying - again. + displayed. Select the \inlineimage icons/action-icon.png + (\uicontrol Actions) menu next to the property name, and then select + \uicontrol Reset to remove the property values before trying again. To modify the common properties of multiple items simultaneously, select them in the \uicontrol Navigator or on the canvas: From 0de98aa240b696d399ed7ed66856ff87f7e596af Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 24 Oct 2019 17:22:49 +0300 Subject: [PATCH 35/57] QmlDesigner: Add overlay display to show position in 3D edit view When dragging using move gizmo, a label is displayed that shows the current position of the selected object. Change-Id: I2e03b363ce9dcb975bcfe198ffae2e98024d74c8 Fixes: QDS-1129 Reviewed-by: Mahmoud Badri Reviewed-by: Thomas Hartmann --- .../qml/qmlpuppet/mockfiles/Arrow.qml | 3 + .../qmlpuppet/mockfiles/AutoScaleHelper.qml | 5 -- .../qml/qmlpuppet/mockfiles/EditView3D.qml | 30 ++++++++++ .../qml/qmlpuppet/mockfiles/MoveGizmo.qml | 1 + .../qml/qmlpuppet/mockfiles/Overlay2D.qml | 59 +++++++++++++++++++ share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc | 1 + 6 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml index 7c9ef095897..ae84b05cb65 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml @@ -35,6 +35,7 @@ Model { property View3D view3D property alias color: material.emissiveColor property Node targetNode: null + property bool isDragging: false readonly property bool hovering: mouseAreaYZ.hovering || mouseAreaXZ.hovering @@ -58,6 +59,7 @@ Model { _pointerPosPressed = mouseArea.mapPositionToScene(maskedPosition); var sp = targetNode.positionInScene; _targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z); + isDragging = true; } function posInParent(mouseArea, pointerPosition) @@ -91,6 +93,7 @@ Model { return; targetNode.position = posInParent(mouseArea, pointerPosition); + isDragging = false; arrow.positionCommit(); } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml index c8d21604d3b..640f560ff80 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml @@ -44,11 +44,6 @@ Node { onGlobalTransformChanged: updateScale() } - Connections { - target: window - onFirstFrameReady: updateScale() - } - function getScale(baseScale) { return Qt.vector3d(baseScale.x * relativeScale, baseScale.y * relativeScale, diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml index b0ec597cba1..dc1ff60cfca 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml @@ -135,6 +135,36 @@ Window { scene: overlayScene } + Overlay2D { + id: gizmoLabel + targetNode: moveGizmo + targetView: overlayView + offsetX: 0 + offsetY: 45 + visible: moveGizmo.isDragging + + Rectangle { + color: "white" + x: -width / 2 + y: -height + width: gizmoLabelText.width + 4 + height: gizmoLabelText.height + 4 + border.width: 1 + Text { + id: gizmoLabelText + text: { + var l = Qt.locale(); + selectedNode + ? qsTr("x:") + Number(selectedNode.position.x).toLocaleString(l, 'f', 1) + + qsTr(" y:") + Number(selectedNode.position.y).toLocaleString(l, 'f', 1) + + qsTr(" z:") + Number(selectedNode.position.z).toLocaleString(l, 'f', 1) + : ""; + } + anchors.centerIn: parent + } + } + } + WasdController { id: cameraControl controlledObject: editView.camera diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml index 62a4e9e7c73..73b80018a92 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml @@ -32,6 +32,7 @@ Node { property View3D view3D property bool highlightOnHover: false property Node targetNode: null + readonly property bool isDragging: arrowX.isDragging || arrowY.isDragging || arrowZ.isDragging scale: Qt.vector3d(5, 5, 5) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml new file mode 100644 index 00000000000..fe9398bfdfd --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick3D 1.0 + +Item { + id: root + property Node targetNode + property View3D targetView + + property real offsetX: 0 + property real offsetY: 0 + + onTargetNodeChanged: updateOverlay() + + Connections { + target: targetNode + onGlobalTransformChanged: updateOverlay() + } + + Connections { + target: targetView.camera + onGlobalTransformChanged: updateOverlay() + } + + function updateOverlay() + { + var posInScene = targetNode.positionInScene + var posInSceneWithOffset = Qt.vector3d(posInScene.x + offsetX, posInScene.y + offsetY, + posInScene.z) + var viewPos = targetView.mapFrom3DScene(posInSceneWithOffset) + root.x = viewPos.x + root.y = viewPos.y + root.z = 100000 - viewPos.z // flip left-handed to right-handed + } +} diff --git a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc index 001591a96d5..03931c280e6 100644 --- a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc +++ b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc @@ -11,6 +11,7 @@ mockfiles/Arrow.qml mockfiles/AutoScaleHelper.qml mockfiles/MoveGizmo.qml + mockfiles/Overlay2D.qml mockfiles/meshes/Arrow.mesh From 4b7f52811a65e634280262e63fa7251ce56da83a Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Wed, 23 Oct 2019 17:22:05 +0200 Subject: [PATCH 36/57] Doc: Update info about connecting MCUs Change-Id: I5b13f7a39534c9721be0ec0b7575943bdafc5795 Reviewed-by: Aurindam Jana --- doc/images/qtcreator-mcu-options.png | Bin 19827 -> 18542 bytes doc/src/mcu/creator-mcu-dev.qdoc | 16 +++++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/doc/images/qtcreator-mcu-options.png b/doc/images/qtcreator-mcu-options.png index e5bcf1f4e6823796b4d3c002a8f4e9db5fcff4a6..f01f189437928a0da0b1244f0aba8bd7f2432cb4 100644 GIT binary patch literal 18542 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 x`~{M+Hb4tWP;zAe Date: Wed, 23 Oct 2019 09:35:02 +0200 Subject: [PATCH 37/57] diffeditor: remove unused forward declaration Change-Id: I9da0e889262e37efae29ee7214edd5d95697e13d Reviewed-by: Orgad Shaneh --- src/plugins/diffeditor/sidebysidediffeditorwidget.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.h b/src/plugins/diffeditor/sidebysidediffeditorwidget.h index 1750a13ba8e..5fbd253e7c3 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.h +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.h @@ -40,7 +40,6 @@ class TextEditorWidget; QT_BEGIN_NAMESPACE class QMenu; class QSplitter; -class QTextBlock; QT_END_NAMESPACE namespace DiffEditor { From 1e22a224030626d23039db5e3c469bb4a639580b Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Wed, 23 Oct 2019 09:33:12 +0200 Subject: [PATCH 38/57] modeleditor: remove unused forward declaration Change-Id: I7c9c6856318145214ce9e76feeb721abed3b4e61 Reviewed-by: Orgad Shaneh --- src/plugins/modeleditor/actionhandler.h | 1 - src/plugins/modeleditor/diagramsviewmanager.h | 2 -- src/plugins/modeleditor/modeleditor.h | 2 -- 3 files changed, 5 deletions(-) diff --git a/src/plugins/modeleditor/actionhandler.h b/src/plugins/modeleditor/actionhandler.h index 192a665839c..5ec858e5356 100644 --- a/src/plugins/modeleditor/actionhandler.h +++ b/src/plugins/modeleditor/actionhandler.h @@ -37,7 +37,6 @@ class QAction; QT_END_NAMESPACE namespace Core { -class ActionContainer; class Command; } diff --git a/src/plugins/modeleditor/diagramsviewmanager.h b/src/plugins/modeleditor/diagramsviewmanager.h index 62ecff23cc2..06a261a08bc 100644 --- a/src/plugins/modeleditor/diagramsviewmanager.h +++ b/src/plugins/modeleditor/diagramsviewmanager.h @@ -31,8 +31,6 @@ #include namespace qmt { -class Uid; -class DiagramView; class MDiagram; } diff --git a/src/plugins/modeleditor/modeleditor.h b/src/plugins/modeleditor/modeleditor.h index a05ab654280..7e91b38daed 100644 --- a/src/plugins/modeleditor/modeleditor.h +++ b/src/plugins/modeleditor/modeleditor.h @@ -42,7 +42,6 @@ class MPackage; class MDiagram; class DElement; class DContainer; -class DocumentController; } namespace ModelEditor { @@ -50,7 +49,6 @@ namespace Internal { class UiController; class ActionHandler; -class DiagramsViewManager; enum class SelectedArea { Nothing, From 80a3c7248e975ae9e4c24b8dc0edd6ab9c3c17b8 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 25 Oct 2019 11:31:07 +0200 Subject: [PATCH 39/57] LanguageClient: Remove unnecessary function re-implementation Change-Id: I44862986a5ecc808b834d7c6d76191cbd9fd07a6 Reviewed-by: David Schulz --- src/plugins/languageclient/languageclienthoverhandler.cpp | 8 -------- src/plugins/languageclient/languageclienthoverhandler.h | 1 - 2 files changed, 9 deletions(-) diff --git a/src/plugins/languageclient/languageclienthoverhandler.cpp b/src/plugins/languageclient/languageclienthoverhandler.cpp index 9f4fc3ad370..3db18c70ff6 100644 --- a/src/plugins/languageclient/languageclienthoverhandler.cpp +++ b/src/plugins/languageclient/languageclienthoverhandler.cpp @@ -96,14 +96,6 @@ void HoverHandler::identifyMatch(TextEditor::TextEditorWidget *editorWidget, m_client->sendContent(request); } -void HoverHandler::operateTooltip(TextEditor::TextEditorWidget *editorWidget, const QPoint &point) -{ - if (toolTip().isEmpty()) - Utils::ToolTip::hide(); - else - Utils::ToolTip::show(point, toolTip(), editorWidget); -} - void HoverHandler::handleResponse(const HoverRequest::Response &response) { m_currentRequest.reset(); diff --git a/src/plugins/languageclient/languageclienthoverhandler.h b/src/plugins/languageclient/languageclienthoverhandler.h index 88a439e2117..c702cd3c585 100644 --- a/src/plugins/languageclient/languageclienthoverhandler.h +++ b/src/plugins/languageclient/languageclienthoverhandler.h @@ -45,7 +45,6 @@ protected: void identifyMatch(TextEditor::TextEditorWidget *editorWidget, int pos, ReportPriority report) override; - void operateTooltip(TextEditor::TextEditorWidget *editorWidget, const QPoint &point) override; private: void handleResponse(const LanguageServerProtocol::HoverRequest::Response &response); From 7f0654e35c694ba4569094b6c135b9a842c35dc6 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 25 Oct 2019 11:33:13 +0200 Subject: [PATCH 40/57] TextEditor: Do not show F1 in tool tips that don't provide help ID(s) Like it is the case for the language client. Utils::TextTip::configure uses QVariant::isNull to check. Change-Id: Ie1e47284a9062e79efcf0debf68486b05bce48ef Reviewed-by: David Schulz --- src/plugins/texteditor/basehoverhandler.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/texteditor/basehoverhandler.cpp b/src/plugins/texteditor/basehoverhandler.cpp index 136fa30e769..05c9f1a52ae 100644 --- a/src/plugins/texteditor/basehoverhandler.cpp +++ b/src/plugins/texteditor/basehoverhandler.cpp @@ -159,7 +159,9 @@ void BaseHoverHandler::operateTooltip(TextEditorWidget *editorWidget, const QPoi Utils::ToolTip::show(point, m_toolTip, editorWidget, - QVariant::fromValue(m_lastHelpItemIdentified)); + m_lastHelpItemIdentified.isEmpty() + ? QVariant() + : QVariant::fromValue(m_lastHelpItemIdentified)); } } // namespace TextEditor From 3476dbd560ecbb5ef276e36de588597f079d0b31 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 25 Oct 2019 10:45:27 +0200 Subject: [PATCH 41/57] LanguageClient: Show markdown tool tips as plain text We tell the language server that we do not support markdown, but some (haskell-ide-engine) ignore that. Show the text as plain text. Change-Id: I1a61346b497cc04dce6c0da4221e949a16c61acf Reviewed-by: David Schulz --- .../languageclient/languageclienthoverhandler.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/plugins/languageclient/languageclienthoverhandler.cpp b/src/plugins/languageclient/languageclienthoverhandler.cpp index 3db18c70ff6..9b53e0f9eca 100644 --- a/src/plugins/languageclient/languageclienthoverhandler.cpp +++ b/src/plugins/languageclient/languageclienthoverhandler.cpp @@ -126,10 +126,13 @@ void HoverHandler::setContent(const HoverContent &hoverContent) { if (auto markupContent = Utils::get_if(&hoverContent)) { const QString &content = markupContent->content(); - if (markupContent->kind() == MarkupKind::plaintext) + if (markupContent->kind() == MarkupKind::plaintext) { setToolTip(content); - else if (m_client) - m_client->log(tr("Got unsupported markup hover content: ") + content); + } else if (m_client) { + m_client->log(tr("Got unsupported markup hover content: ") + content, + Core::MessageManager::Silent); + setToolTip(content); + } } else if (auto markedString = Utils::get_if(&hoverContent)) { setToolTip(toolTipForMarkedStrings({*markedString})); } else if (auto markedStrings = Utils::get_if>(&hoverContent)) { From baced09bc7b9095c7df64c5f767a3bc894d3783c Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 25 Oct 2019 11:45:52 +0300 Subject: [PATCH 42/57] QmlDesigner: Fix edit view issues caused by quick3d api changes Change-Id: I4bb110ff4693c57089f659e0f125c9f89c6bdb9c Reviewed-by: Mahmoud Badri Reviewed-by: Thomas Hartmann --- .../qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml | 2 +- .../qml/qmlpuppet/mockfiles/AutoScaleHelper.qml | 10 +++++----- .../qml/qmlpuppet/mockfiles/EditView3D.qml | 6 +++--- .../qml/qmlpuppet/mockfiles/Overlay2D.qml | 17 ++++++++--------- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml index ae84b05cb65..dc2fee64543 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml @@ -57,7 +57,7 @@ Model { var maskedPosition = Qt.vector3d(pointerPosition.x, 0, 0); _pointerPosPressed = mouseArea.mapPositionToScene(maskedPosition); - var sp = targetNode.positionInScene; + var sp = targetNode.scenePosition; _targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z); isDragging = true; } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml index 640f560ff80..2e8425016df 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml @@ -37,11 +37,11 @@ Node { // Read-only property real relativeScale: 1 - onGlobalTransformChanged: updateScale() + onSceneTransformChanged: updateScale() onAutoScaleChanged: updateScale() Connections { target: view3D.camera - onGlobalTransformChanged: updateScale() + onSceneTransformChanged: updateScale() } function getScale(baseScale) @@ -60,16 +60,16 @@ Node { // "anchor" distance. Map the two positions back to the target node, and measure the // distance between them now, in the 3D scene. The difference of the two distances, // view and scene, will tell us what the distance independent scale should be. - var posInView1 = view3D.mapFrom3DScene(positionInScene); + var posInView1 = view3D.mapFrom3DScene(scenePosition); var posInView2 = Qt.vector3d(posInView1.x + 100, posInView1.y, posInView1.z); var rayPos1 = view3D.mapTo3DScene(Qt.vector3d(posInView2.x, posInView2.y, 0)); var rayPos2 = view3D.mapTo3DScene(Qt.vector3d(posInView2.x, posInView2.y, 10)); var planeNormal = view3D.camera.forward; - var rayHitPos = helper.rayIntersectsPlane(rayPos1, rayPos2, positionInScene, + var rayHitPos = helper.rayIntersectsPlane(rayPos1, rayPos2, scenePosition, planeNormal); - relativeScale = positionInScene.minus(rayHitPos).length() / 100; + relativeScale = scenePosition.minus(rayHitPos).length() / 100; } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml index dc1ff60cfca..59d3c662081 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml @@ -64,11 +64,11 @@ Window { scale: autoScale.getScale(Qt.vector3d(5, 5, 5)) highlightOnHover: true targetNode: viewWindow.selectedNode - position: viewWindow.selectedNode ? viewWindow.selectedNode.positionInScene + position: viewWindow.selectedNode ? viewWindow.selectedNode.scenePosition : Qt.vector3d(0, 0, 0) rotation: globalControl.checked || !viewWindow.selectedNode ? Qt.vector3d(0, 0, 0) - : viewWindow.selectedNode.rotationInScene + : viewWindow.selectedNode.sceneRotation visible: selectedNode view3D: overlayView @@ -79,7 +79,7 @@ Window { AutoScaleHelper { id: autoScale view3D: overlayView - position: moveGizmo.positionInScene + position: moveGizmo.scenePosition } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml index fe9398bfdfd..7e1e231133a 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml @@ -38,22 +38,21 @@ Item { Connections { target: targetNode - onGlobalTransformChanged: updateOverlay() + onSceneTransformChanged: updateOverlay() } Connections { target: targetView.camera - onGlobalTransformChanged: updateOverlay() + onSceneTransformChanged: updateOverlay() } function updateOverlay() { - var posInScene = targetNode.positionInScene - var posInSceneWithOffset = Qt.vector3d(posInScene.x + offsetX, posInScene.y + offsetY, - posInScene.z) - var viewPos = targetView.mapFrom3DScene(posInSceneWithOffset) - root.x = viewPos.x - root.y = viewPos.y - root.z = 100000 - viewPos.z // flip left-handed to right-handed + var scenePos = targetNode.scenePosition; + var scenePosWithOffset = Qt.vector3d(scenePos.x + offsetX, scenePos.y + offsetY, scenePos.z); + var viewPos = targetView.mapFrom3DScene(scenePosWithOffset); + root.x = viewPos.x; + root.y = viewPos.y; + root.z = 100000 - viewPos.z; // flip left-handed to right-handed } } From 088d5c0f779edc12605a04486d223749c3158152 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 25 Oct 2019 13:18:29 +0200 Subject: [PATCH 43/57] TextEditor: Fix HTML escaping of tool tips Tool tips without help ID were HTML escaped but never shown in a HTML tool tip. Just always make them rich text. Line endings in plain text must be changed to "
" as well. Change-Id: I9fd378e2c9a58ddf5834d67927fe3da9157cfbc7 Reviewed-by: David Schulz --- src/plugins/texteditor/basehoverhandler.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/plugins/texteditor/basehoverhandler.cpp b/src/plugins/texteditor/basehoverhandler.cpp index 05c9f1a52ae..d7d53ca5f0c 100644 --- a/src/plugins/texteditor/basehoverhandler.cpp +++ b/src/plugins/texteditor/basehoverhandler.cpp @@ -142,12 +142,15 @@ void BaseHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos, Re void BaseHoverHandler::decorateToolTip() { - m_toolTip = m_toolTip.toHtmlEscaped(); + if (!m_toolTip.isEmpty()) + m_toolTip = "

" + m_toolTip.toHtmlEscaped().replace('\n', "
") + "

"; if (lastHelpItemIdentified().isValid() && !lastHelpItemIdentified().isFuzzyMatch()) { const QString &helpContents = lastHelpItemIdentified().extractContent(false); - if (!helpContents.isEmpty()) - m_toolTip = m_toolTip.isEmpty() ? helpContents : ("

" + m_toolTip + "


" + helpContents + "

"); + if (!helpContents.isEmpty()) { + m_toolTip = m_toolTip.isEmpty() ? helpContents + : (m_toolTip + "

" + helpContents + "

"); + } } } From 10c94994db84c920ebf1ff43b6b5fe5224ee8afa Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 18 Oct 2019 10:31:14 +0200 Subject: [PATCH 44/57] Python: close all info bars after language server setup Change-Id: I607f7cb5a31f3db0c7d7d77011860a1ea87eb8d2 Reviewed-by: Christian Stenger --- src/plugins/python/pythoneditor.cpp | 15 +- src/plugins/python/pythonplugin.cpp | 13 ++ src/plugins/python/pythonplugin.h | 4 +- src/plugins/python/pythonrunconfiguration.cpp | 15 +- src/plugins/python/pythonutils.cpp | 129 ++++++++++++------ src/plugins/python/pythonutils.h | 40 ++++-- 6 files changed, 134 insertions(+), 82 deletions(-) diff --git a/src/plugins/python/pythoneditor.cpp b/src/plugins/python/pythoneditor.cpp index 6481897e699..eea74c17868 100644 --- a/src/plugins/python/pythoneditor.cpp +++ b/src/plugins/python/pythoneditor.cpp @@ -35,19 +35,6 @@ namespace Python { namespace Internal { -static void documentOpened(Core::IDocument *document) -{ - auto textDocument = qobject_cast(document); - if (!textDocument || textDocument->mimeType() != Constants::C_PY_MIMETYPE) - return; - - const Utils::FilePath &python = detectPython(textDocument->filePath()); - if (!python.exists()) - return; - - updateEditorInfoBar(python, textDocument); -} - PythonEditorFactory::PythonEditorFactory() { setId(Constants::C_PYTHONEDITOR_ID); @@ -68,7 +55,7 @@ PythonEditorFactory::PythonEditorFactory() setCodeFoldingSupported(true); connect(Core::EditorManager::instance(), &Core::EditorManager::documentOpened, - this, documentOpened); + this, &PyLSConfigureAssistant::documentOpened); } } // namespace Internal diff --git a/src/plugins/python/pythonplugin.cpp b/src/plugins/python/pythonplugin.cpp index bdb0d6a32e6..63d7c663c2e 100644 --- a/src/plugins/python/pythonplugin.cpp +++ b/src/plugins/python/pythonplugin.cpp @@ -51,6 +51,8 @@ namespace Internal { // //////////////////////////////////////////////////////////////////////////////////// +static PythonPlugin *m_instance = nullptr; + class PythonPluginPrivate { public: @@ -65,11 +67,22 @@ public: }; }; +PythonPlugin::PythonPlugin() +{ + m_instance = this; +} + PythonPlugin::~PythonPlugin() { + m_instance = nullptr; delete d; } +PythonPlugin *PythonPlugin::instance() +{ + return m_instance; +} + bool PythonPlugin::initialize(const QStringList &arguments, QString *errorMessage) { Q_UNUSED(arguments) diff --git a/src/plugins/python/pythonplugin.h b/src/plugins/python/pythonplugin.h index 5b2e395d917..c0d79d7a874 100644 --- a/src/plugins/python/pythonplugin.h +++ b/src/plugins/python/pythonplugin.h @@ -36,9 +36,11 @@ class PythonPlugin : public ExtensionSystem::IPlugin Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Python.json") public: - PythonPlugin() = default; + PythonPlugin(); ~PythonPlugin() final; + static PythonPlugin *instance(); + private: bool initialize(const QStringList &arguments, QString *errorMessage) final; void extensionsInitialized() final; diff --git a/src/plugins/python/pythonrunconfiguration.cpp b/src/plugins/python/pythonrunconfiguration.cpp index 53245b16323..d9e78c16726 100644 --- a/src/plugins/python/pythonrunconfiguration.cpp +++ b/src/plugins/python/pythonrunconfiguration.cpp @@ -297,23 +297,10 @@ void PythonRunConfiguration::updateLanguageServer() const FilePath python(FilePath::fromUserInput(interpreter())); - if (const StdIOSettings *lsSetting = languageServerForPython(python)) { - if (Client *client = LanguageClientManager::clientForSetting(lsSetting).value(0)) { - for (FilePath &file : project()->files(Project::AllFiles)) { - if (auto document = TextEditor::TextDocument::textDocumentForFilePath(file)) { - if (document->mimeType() == Constants::C_PY_MIMETYPE) { - resetEditorInfoBar(document); - LanguageClientManager::reOpenDocumentWithClient(document, client); - } - } - } - } - } - for (FilePath &file : project()->files(Project::AllFiles)) { if (auto document = TextEditor::TextDocument::textDocumentForFilePath(file)) { if (document->mimeType() == Constants::C_PY_MIMETYPE) - updateEditorInfoBar(python, document); + PyLSConfigureAssistant::instance()->openDocumentWithPython(python, document); } } } diff --git a/src/plugins/python/pythonutils.cpp b/src/plugins/python/pythonutils.cpp index 0af6d5fd5a9..82fa67d93ab 100644 --- a/src/plugins/python/pythonutils.cpp +++ b/src/plugins/python/pythonutils.cpp @@ -26,6 +26,7 @@ #include "pythonutils.h" #include "pythonconstants.h" +#include "pythonplugin.h" #include "pythonproject.h" #include "pythonrunconfiguration.h" #include "pythonsettings.h" @@ -33,8 +34,8 @@ #include #include -#include #include +#include #include #include @@ -49,6 +50,7 @@ #include #include +using namespace LanguageClient; using namespace Utils; namespace Python { @@ -58,7 +60,6 @@ static constexpr char startPylsInfoBarId[] = "Python::StartPyls"; static constexpr char installPylsInfoBarId[] = "Python::InstallPyls"; static constexpr char enablePylsInfoBarId[] = "Python::EnablePyls"; static constexpr char installPylsTaskId[] = "Python::InstallPylsTask"; -static constexpr char pythonUtilsTrContext[] = "Python::Utils"; struct PythonLanguageServerState { @@ -116,7 +117,7 @@ FilePath getPylsModulePath(CommandLine pylsCommand) return {}; } -QList configuredPythonLanguageServer() +QList configuredPythonLanguageServer() { using namespace LanguageClient; QList result; @@ -156,7 +157,7 @@ static PythonLanguageServerState checkPythonLanguageServer(const FilePath &pytho return {PythonLanguageServerState::CanNotBeInstalled, FilePath()}; } -FilePath detectPython(const FilePath &documentPath) +static FilePath detectPython(const FilePath &documentPath) { FilePath python; @@ -183,26 +184,33 @@ FilePath detectPython(const FilePath &documentPath) return python; } -const LanguageClient::StdIOSettings *languageServerForPython(const FilePath &python) +PyLSConfigureAssistant *PyLSConfigureAssistant::instance() +{ + static auto *instance = new PyLSConfigureAssistant(PythonPlugin::instance()); + return instance; +} + +const StdIOSettings *PyLSConfigureAssistant::languageServerForPython(const FilePath &python) { return findOrDefault(configuredPythonLanguageServer(), - [pythonModulePath = getPylsModulePath(CommandLine(python, {"-m", "pyls"}))]( - const LanguageClient::StdIOSettings *setting) { + [pythonModulePath = getPylsModulePath( + CommandLine(python, {"-m", "pyls"}))](const StdIOSettings *setting) { return getPylsModulePath(setting->command()) == pythonModulePath; }); } -static LanguageClient::Client *registerLanguageServer(const FilePath &python) +static Client *registerLanguageServer(const FilePath &python) { - auto *settings = new LanguageClient::StdIOSettings(); + auto *settings = new StdIOSettings(); settings->m_executable = python.toString(); settings->m_arguments = "-m pyls"; - settings->m_name = QCoreApplication::translate(pythonUtilsTrContext, - "Python Language Server (%1)") + settings->m_name = PyLSConfigureAssistant::tr("Python Language Server (%1)") .arg(pythonName(python)); settings->m_languageFilter.mimeTypes = QStringList(Constants::C_PY_MIMETYPE); - LanguageClient::LanguageClientManager::registerClientSettings(settings); - return LanguageClient::LanguageClientManager::clientForSetting(settings).value(0); + LanguageClientManager::registerClientSettings(settings); + Client *client = LanguageClientManager::clientForSetting(settings).value(0); + PyLSConfigureAssistant::updateEditorInfoBars(python, client); + return client; } class PythonLSInstallHelper : public QObject @@ -253,17 +261,16 @@ private: void cancel() { SynchronousProcess::stopProcess(m_process); - Core::MessageManager::write( - tr("The Python language server installation canceled by %1.") - .arg(m_killTimer.isActive() ? tr("user") : tr("time out"))); + Core::MessageManager::write(tr("The Python language server installation canceled by %1.") + .arg(m_killTimer.isActive() ? tr("user") : tr("time out"))); } void installFinished(int exitCode, QProcess::ExitStatus exitStatus) { m_future.reportFinished(); if (exitStatus == QProcess::NormalExit && exitCode == 0) { - if (LanguageClient::Client *client = registerLanguageServer(m_python)) - LanguageClient::LanguageClientManager::reOpenDocumentWithClient(m_document, client); + if (Client *client = registerLanguageServer(m_python)) + LanguageClientManager::reOpenDocumentWithClient(m_document, client); } else { Core::MessageManager::write( tr("Installing the Python language server failed with exit code %1").arg(exitCode)); @@ -293,11 +300,16 @@ private: QPointer m_document; }; -static void installPythonLanguageServer(const FilePath &python, - QPointer document) +void PyLSConfigureAssistant::installPythonLanguageServer(const FilePath &python, + QPointer document) { document->infoBar()->removeInfo(installPylsInfoBarId); + // Hide all install info bar entries for this python, but keep them in the list + // so the language server will be setup properly after the installation is done. + for (TextEditor::TextDocument *additionalDocument : m_infoBarEntries[python]) + additionalDocument->infoBar()->removeInfo(installPylsInfoBarId); + auto install = new PythonLSInstallHelper(python, document); install->run(); } @@ -306,36 +318,49 @@ static void setupPythonLanguageServer(const FilePath &python, QPointer document) { document->infoBar()->removeInfo(startPylsInfoBarId); - if (LanguageClient::Client *client = registerLanguageServer(python)) - LanguageClient::LanguageClientManager::reOpenDocumentWithClient(document, client); + if (Client *client = registerLanguageServer(python)) + LanguageClientManager::reOpenDocumentWithClient(document, client); } static void enablePythonLanguageServer(const FilePath &python, QPointer document) { - using namespace LanguageClient; document->infoBar()->removeInfo(enablePylsInfoBarId); - if (const StdIOSettings *setting = languageServerForPython(python)) { + if (const StdIOSettings *setting = PyLSConfigureAssistant::languageServerForPython(python)) { LanguageClientManager::enableClientSettings(setting->m_id); - if (const StdIOSettings *setting = languageServerForPython(python)) { - if (Client *client = LanguageClientManager::clientForSetting(setting).value(0)) + if (const StdIOSettings *setting = PyLSConfigureAssistant::languageServerForPython(python)) { + if (Client *client = LanguageClientManager::clientForSetting(setting).value(0)) { LanguageClientManager::reOpenDocumentWithClient(document, client); + PyLSConfigureAssistant::updateEditorInfoBars(python, client); + } } } } -void updateEditorInfoBar(const FilePath &python, TextEditor::TextDocument *document) +void PyLSConfigureAssistant::documentOpened(Core::IDocument *document) +{ + auto textDocument = qobject_cast(document); + if (!textDocument || textDocument->mimeType() != Constants::C_PY_MIMETYPE) + return; + + const FilePath &python = detectPython(textDocument->filePath()); + if (!python.exists()) + return; + + instance()->openDocumentWithPython(python, textDocument); +} + +void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python, + TextEditor::TextDocument *document) { const PythonLanguageServerState &lsState = checkPythonLanguageServer(python); if (lsState.state == PythonLanguageServerState::CanNotBeInstalled) return; if (lsState.state == PythonLanguageServerState::AlreadyConfigured) { - if (const LanguageClient::StdIOSettings *setting = languageServerForPython(python)) { - if (LanguageClient::Client *client - = LanguageClient::LanguageClientManager::clientForSetting(setting).value(0)) { - LanguageClient::LanguageClientManager::reOpenDocumentWithClient(document, client); - } + if (const StdIOSettings *setting = languageServerForPython(python)) { + if (Client *client = LanguageClientManager::clientForSetting(setting).value(0)) + LanguageClientManager::reOpenDocumentWithClient(document, client); } return; } @@ -345,52 +370,66 @@ void updateEditorInfoBar(const FilePath &python, TextEditor::TextDocument *docum if (lsState.state == PythonLanguageServerState::CanBeInstalled && infoBar->canInfoBeAdded(installPylsInfoBarId)) { auto message - = QCoreApplication::translate(pythonUtilsTrContext, - "Install and set up Python language server (PyLS) for %1 (%2). " - "The language server provides Python specific completions and annotations.") + = tr("Install and set up Python language server (PyLS) for %1 (%2). " + "The language server provides Python specific completions and annotations.") .arg(pythonName(python), python.toUserOutput()); Core::InfoBarEntry info(installPylsInfoBarId, message, Core::InfoBarEntry::GlobalSuppression::Enabled); - info.setCustomButtonInfo(QCoreApplication::translate(pythonUtilsTrContext, "Install"), + info.setCustomButtonInfo(tr("Install"), [=]() { installPythonLanguageServer(python, document); }); infoBar->addInfo(info); + m_infoBarEntries[python] << document; } else if (lsState.state == PythonLanguageServerState::AlreadyInstalled && infoBar->canInfoBeAdded(startPylsInfoBarId)) { - auto message = QCoreApplication::translate(pythonUtilsTrContext, - "Found a Python language server for %1 (%2). " - "Should this one be set up for this document?") + auto message = tr("Found a Python language server for %1 (%2). " + "Should this one be set up for this document?") .arg(pythonName(python), python.toUserOutput()); Core::InfoBarEntry info(startPylsInfoBarId, message, Core::InfoBarEntry::GlobalSuppression::Enabled); - info.setCustomButtonInfo(QCoreApplication::translate(pythonUtilsTrContext, "Setup"), + info.setCustomButtonInfo(tr("Setup"), [=]() { setupPythonLanguageServer(python, document); }); infoBar->addInfo(info); + m_infoBarEntries[python] << document; } else if (lsState.state == PythonLanguageServerState::ConfiguredButDisabled && infoBar->canInfoBeAdded(enablePylsInfoBarId)) { - auto message = QCoreApplication::translate(pythonUtilsTrContext, - "Enable Python language server for %1 (%2)?") + auto message = tr("Enable Python language server for %1 (%2)?") .arg(pythonName(python), python.toUserOutput()); Core::InfoBarEntry info(enablePylsInfoBarId, message, Core::InfoBarEntry::GlobalSuppression::Enabled); - info.setCustomButtonInfo(QCoreApplication::translate(pythonUtilsTrContext, "Enable"), + info.setCustomButtonInfo(tr("Enable"), [=]() { enablePythonLanguageServer(python, document); }); infoBar->addInfo(info); + m_infoBarEntries[python] << document; } } -void resetEditorInfoBar(TextEditor::TextDocument *document) +void PyLSConfigureAssistant::updateEditorInfoBars(const FilePath &python, Client *client) { + for (TextEditor::TextDocument *document : instance()->m_infoBarEntries.take(python)) { + instance()->resetEditorInfoBar(document); + if (client) + LanguageClientManager::reOpenDocumentWithClient(document, client); + } +} + +void PyLSConfigureAssistant::resetEditorInfoBar(TextEditor::TextDocument *document) +{ + for (QList &documents : m_infoBarEntries) + documents.removeAll(document); Core::InfoBar *infoBar = document->infoBar(); infoBar->removeInfo(installPylsInfoBarId); infoBar->removeInfo(startPylsInfoBarId); infoBar->removeInfo(enablePylsInfoBarId); } +PyLSConfigureAssistant::PyLSConfigureAssistant(QObject *parent) + : QObject(parent) +{} + } // namespace Internal } // namespace Python #include "pythonutils.moc" - diff --git a/src/plugins/python/pythonutils.h b/src/plugins/python/pythonutils.h index f376a4d7492..20cb674ddb9 100644 --- a/src/plugins/python/pythonutils.h +++ b/src/plugins/python/pythonutils.h @@ -23,21 +23,45 @@ ** ****************************************************************************/ -#include - #pragma once +#include + +#include +#include + +namespace Core { class IDocument; } +namespace LanguageClient { +class Client; +class StdIOSettings; +} namespace TextEditor { class TextDocument; } -namespace LanguageClient { class StdIOSettings; } namespace Python { namespace Internal { -QList configuredPythonLanguageServers(); -const LanguageClient::StdIOSettings *languageServerForPython(const Utils::FilePath &python); -Utils::FilePath detectPython(const Utils::FilePath &NdocumentPath); -void updateEditorInfoBar(const Utils::FilePath &python, TextEditor::TextDocument *document); -void resetEditorInfoBar(TextEditor::TextDocument *document); +class PyLSConfigureAssistant : public QObject +{ + Q_OBJECT +public: + static PyLSConfigureAssistant *instance(); + + static const LanguageClient::StdIOSettings *languageServerForPython( + const Utils::FilePath &python); + static void documentOpened(Core::IDocument *document); + static void updateEditorInfoBars(const Utils::FilePath &python, LanguageClient::Client *client); + + void openDocumentWithPython(const Utils::FilePath &python, TextEditor::TextDocument *document); + +private: + explicit PyLSConfigureAssistant(QObject *parent); + + void resetEditorInfoBar(TextEditor::TextDocument *document); + void installPythonLanguageServer(const Utils::FilePath &python, + QPointer document); + + QHash> m_infoBarEntries; +}; } // namespace Internal } // namespace Python From 01df962d6a6f35cea25efefd7b51d7dcfe104407 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 24 Oct 2019 10:57:17 +0200 Subject: [PATCH 45/57] Python: install python language server with --user Change-Id: Ifd8e19ea7d52d85ec0c497e5cbfe24300571398e Reviewed-by: Christian Stenger --- src/plugins/python/pythonutils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/python/pythonutils.cpp b/src/plugins/python/pythonutils.cpp index 82fa67d93ab..03096ee96e9 100644 --- a/src/plugins/python/pythonutils.cpp +++ b/src/plugins/python/pythonutils.cpp @@ -248,7 +248,7 @@ public: ? QString{"python-language-server[pyflakes]"} : QString{"python-language-server[all]"}; - m_process.start(m_python.toString(), {"-m", "pip", "install", pylsVersion}); + m_process.start(m_python.toString(), {"-m", "pip", "install", "--user", pylsVersion}); Core::MessageManager::write(tr("Running '%1 %2' to install python language server") .arg(m_process.program(), m_process.arguments().join(' '))); From 95bd328c31432a952c58dbec7dc460b9fcafc313 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 24 Oct 2019 14:28:58 +0200 Subject: [PATCH 46/57] Python: export Interpreter generator Change-Id: I591bd6c14706e1699f028a9a3a6dfd9b89eec66a Reviewed-by: Christian Stenger --- src/plugins/python/pythonsettings.cpp | 24 ++++++++++++++---------- src/plugins/python/pythonsettings.h | 10 +++++++++- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index be1ad7b4ee9..d9ab47093c9 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -272,15 +272,14 @@ static bool alreadyRegistered(const QList &pythons, const FilePath }); } -Interpreter interpreterForPythonExecutable(const FilePath &python, - const QString &defaultName, - bool windowedSuffix = false) +Interpreter::Interpreter(const FilePath &python, const QString &defaultName, bool windowedSuffix) + : id(QUuid::createUuid().toString()) + , command(python) { SynchronousProcess pythonProcess; pythonProcess.setProcessChannelMode(QProcess::MergedChannels); SynchronousProcessResponse response = pythonProcess.runBlocking( CommandLine(python, {"--version"})); - QString name; if (response.result == SynchronousProcessResponse::Finished) name = response.stdOut().trimmed(); if (name.isEmpty()) @@ -290,9 +289,14 @@ Interpreter interpreterForPythonExecutable(const FilePath &python, QDir pythonDir(python.parentDir().toString()); if (pythonDir.exists() && pythonDir.exists("activate") && pythonDir.cdUp()) name += QString(" (%1 Virtual Environment)").arg(pythonDir.dirName()); - return Interpreter{QUuid::createUuid().toString(), name, python}; } +Interpreter::Interpreter(const QString &_id, const QString &_name, const FilePath &_command) + : id(_id) + , name(_name) + , command(_command) +{} + static InterpreterOptionsPage &interpreterOptionsPage() { static InterpreterOptionsPage page; @@ -388,11 +392,11 @@ static void addPythonsFromRegistry(QList &pythons) const FilePath &path = FilePath::fromUserInput(regVal.toString()); const FilePath &python = path.pathAppended(HostOsInfo::withExecutableSuffix("python")); if (python.exists() && !alreadyRegistered(pythons, python)) - pythons << interpreterForPythonExecutable(python, "Python " + versionGroup); + pythons << Interpreter(python, "Python " + versionGroup); const FilePath &pythonw = path.pathAppended( HostOsInfo::withExecutableSuffix("pythonw")); if (pythonw.exists() && !alreadyRegistered(pythons, pythonw)) - pythons << interpreterForPythonExecutable(pythonw, "Python " + versionGroup, true); + pythons << Interpreter(pythonw, "Python " + versionGroup, true); } pythonRegistry.endGroup(); } @@ -405,11 +409,11 @@ static void addPythonsFromPath(QList &pythons) if (HostOsInfo::isWindowsHost()) { for (const FilePath &executable : env.findAllInPath("python")) { if (executable.exists() && !alreadyRegistered(pythons, executable)) - pythons << interpreterForPythonExecutable(executable, "Python from Path"); + pythons << Interpreter(executable, "Python from Path"); } for (const FilePath &executable : env.findAllInPath("pythonw")) { if (executable.exists() && !alreadyRegistered(pythons, executable)) - pythons << interpreterForPythonExecutable(executable, "Python from Path", true); + pythons << Interpreter(executable, "Python from Path", true); } } else { const QStringList filters = {"python", @@ -421,7 +425,7 @@ static void addPythonsFromPath(QList &pythons) for (const QFileInfo &fi : dir.entryInfoList(filters)) { const FilePath executable = Utils::FilePath::fromFileInfo(fi); if (executable.exists() && !alreadyRegistered(pythons, executable)) - pythons << interpreterForPythonExecutable(executable, "Python from Path"); + pythons << Interpreter(executable, "Python from Path"); } } } diff --git a/src/plugins/python/pythonsettings.h b/src/plugins/python/pythonsettings.h index 583d4fb212f..7ca5218ae39 100644 --- a/src/plugins/python/pythonsettings.h +++ b/src/plugins/python/pythonsettings.h @@ -35,7 +35,15 @@ namespace Internal { class Interpreter { public: - QString id; + Interpreter() = default; + Interpreter(const Utils::FilePath &python, + const QString &defaultName, + bool windowedSuffix = false); + Interpreter(const QString &id, + const QString &name, + const Utils::FilePath &command); + + QString id = QUuid::createUuid().toString(); QString name; Utils::FilePath command; }; From a9e9100481f23d3cd64f3694850f03b73e9ccf70 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 25 Oct 2019 15:45:29 +0200 Subject: [PATCH 47/57] QmlDesigner: Use fuzzy compare for floats This fixes a soft assert when comparing floats. Change-Id: Id1626ab0ad2d777e6b67983210becdc8a32a95d2 Reviewed-by: Thomas Hartmann --- .../qmldesigner/designercore/model/texttomodelmerger.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp index b2e5e3a8b84..69bc9ff0f92 100644 --- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp @@ -356,7 +356,10 @@ bool compareJavaScriptExpression(const QString &expression1, const QString &expr bool smartVeryFuzzyCompare(const QVariant &value1, const QVariant &value2) { //we ignore slight changes on doubles and only check three digits - if ((value1.type() == QVariant::Double) || (value2.type() == QVariant::Double)) { + if ((value1.type() == QMetaType::Double) + || (value2.type() == QMetaType::Double) + || (value1.type() == QMetaType::Float) + || (value2.type() == QMetaType::Float)) { bool ok1, ok2; qreal a = value1.toDouble(&ok1); qreal b = value2.toDouble(&ok2); From e5727777763f0aa99961be53a153b3288e5c5c43 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 25 Oct 2019 10:08:54 +0200 Subject: [PATCH 48/57] QmlDesigner: Fix setting position from qml2puppet Change-Id: I1348fa3d761be7b185d5324a73e8cdd543be50e9 Reviewed-by: Miikka Heikkinen Reviewed-by: Mahmoud Badri Reviewed-by: Thomas Hartmann --- .../qt5informationnodeinstanceserver.cpp | 46 +++++++++++++++---- .../qt5informationnodeinstanceserver.h | 3 ++ 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 0cb95c98d9c..8dc4ab79099 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -63,6 +63,7 @@ #include +#include #include #include #include @@ -118,18 +119,45 @@ void Qt5InformationNodeInstanceServer::objectClicked(const QVariant &object) selectInstance(instance); } +QVector +Qt5InformationNodeInstanceServer::vectorToPropertyValue( + const ServerNodeInstance &instance, + const PropertyName &propertyName, + const QVariant &variant) +{ + QVector result; + + auto vector3d = variant.value(); + + if (vector3d.isNull()) + return result; + + const PropertyName dot = propertyName.isEmpty() ? "" : "."; + + InstancePropertyValueTriple propTriple; + propTriple.instance = instance; + propTriple.propertyName = propertyName + dot + PropertyName("x"); + propTriple.propertyValue = vector3d.x(); + result.append(propTriple); + propTriple.propertyName = propertyName + dot + PropertyName("y"); + propTriple.propertyValue = vector3d.y(); + result.append(propTriple); + propTriple.propertyName = propertyName + dot + PropertyName("z"); + propTriple.propertyValue = vector3d.z(); + result.append(propTriple); + + return result; +} + void Qt5InformationNodeInstanceServer::handleObjectPositionCommit(const QVariant &object) { - QObject *obj = object.value(); + auto *obj = object.value(); if (obj) { - ServerNodeInstance instance = instanceForObject(obj); - QVector modifiedpropertyList; - InstancePropertyValueTriple propTriple; - propTriple.instance = instance; - propTriple.propertyName = "position"; - propTriple.propertyValue = obj->property(propTriple.propertyName.constData()); - modifiedpropertyList.append(propTriple); - nodeInstanceClient()->valuesModified(createValuesModifiedCommand(modifiedpropertyList)); + /* We do have to split position into position.x, position.y, position.z */ + nodeInstanceClient()->valuesModified(createValuesModifiedCommand(vectorToPropertyValue( + instanceForObject(obj), + "position", + obj->property("position")))); } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index 243b3339049..7a9334acc07 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -61,6 +61,9 @@ private: QObject *createEditView3D(QQmlEngine *engine); void setup3DEditView(const QList &instanceList); QObject *findRootNodeOf3DViewport(const QList &instanceList) const; + QVector vectorToPropertyValue(const ServerNodeInstance &instance, + const PropertyName &propertyName, + const QVariant &variant); QSet m_parentChangedSet; QList m_completedComponentList; From b6aa4e2370b9110b92c7ae87e348cbf4a84feef5 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 25 Oct 2019 08:19:52 +0200 Subject: [PATCH 49/57] LanguageClient: Avoid problems with old settings Empty file pattern entries may end up in a match everything state, so remove them if they are still present inside old settings. Change-Id: Ic388522aa152265b5d10a9e334acd3e7b7032be7 Reviewed-by: David Schulz --- src/plugins/languageclient/languageclientsettings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index a08e52208fc..fcd3a07b4ac 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -530,6 +530,7 @@ void BaseSettings::fromMap(const QVariantMap &map) map.value(startupBehaviorKey, BaseSettings::RequiresFile).toInt()); m_languageFilter.mimeTypes = map[mimeTypeKey].toStringList(); m_languageFilter.filePattern = map[filePatternKey].toStringList(); + m_languageFilter.filePattern.removeAll({}); // remove empty entries } static LanguageClientSettingsPage &settingsPage() From afd22a75c18ad15293ed612f0a85a52a45e37881 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Fri, 25 Oct 2019 15:25:21 +0300 Subject: [PATCH 50/57] Update EditView3D when selecting a 3D object in the navigator Task-number: QDS-1124 Change-Id: I8d7bf73612b07592cd9beb85a5249895a400316b Reviewed-by: Miikka Heikkinen Reviewed-by: Thomas Hartmann --- .../qml/qmlpuppet/mockfiles/EditView3D.qml | 6 +++- .../qt5informationnodeinstanceserver.cpp | 31 ++++++++++++++----- .../qt5informationnodeinstanceserver.h | 1 + 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml index 59d3c662081..a0a9c0e5998 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml @@ -47,6 +47,10 @@ Window { signal objectClicked(var object) signal commitObjectPosition(var object) + function selectObject(object) { + selectedNode = object; + } + Node { id: overlayScene @@ -94,7 +98,7 @@ Window { var pickResult = editView.pick(eventPoint.scenePosition.x, eventPoint.scenePosition.y); viewWindow.objectClicked(pickResult.objectHit); - selectedNode = pickResult.objectHit; // TODO selection needs to come from studio + selectObject(pickResult.objectHit); } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 8dc4ab79099..b1fa8be60d5 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -267,17 +267,17 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QListsetParent(view); + QQmlProperty sceneProperty(m_editView3D, "scene", context()); + node->setParent(m_editView3D); sceneProperty.write(objectToVariant(node)); QQmlProperty parentProperty(node, "parent", context()); - parentProperty.write(objectToVariant(view)); - QQmlProperty completeSceneProperty(view, "showLight", context()); + parentProperty.write(objectToVariant(m_editView3D)); + QQmlProperty completeSceneProperty(m_editView3D, "showLight", context()); completeSceneProperty.write(showCustomLight); } } @@ -452,8 +452,23 @@ void QmlDesigner::Qt5InformationNodeInstanceServer::removeSharedMemory(const Qml void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionCommand &command) { - // keep track of selection. - qDebug() << Q_FUNC_INFO << command; + if (!m_editView3D) + return; + + const QVector instanceIds = command.instanceIds(); + for (qint32 id : instanceIds) { + if (hasInstanceForId(id)) { + ServerNodeInstance instance = instanceForId(id); + QObject *object = nullptr; + if (instance.isSubclassOf("QQuick3DModel") || instance.isSubclassOf("QQuick3DCamera") + || instance.isSubclassOf("QQuick3DAbstractLight")) { + object = instance.internalObject(); + } + QMetaObject::invokeMethod(m_editView3D, "selectObject", Q_ARG(QVariant, + objectToVariant(object))); + return; // TODO: support multi-selection + } + } } } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index 7a9334acc07..c574a6ed11d 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -65,6 +65,7 @@ private: const PropertyName &propertyName, const QVariant &variant); + QObject *m_editView3D = nullptr; QSet m_parentChangedSet; QList m_completedComponentList; QList m_tokenList; From e3904f3b135564834ae78245d79818e72d2edd7b Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Fri, 18 Oct 2019 09:25:14 +0300 Subject: [PATCH 51/57] CMake: Add Android Multi ABI support Change-Id: Ia5b3fcda29705fefca85833ebc28b4154defba5f Reviewed-by: Cristian Adam Reviewed-by: Alexandru Croitor Reviewed-by: Alessandro Portale --- .../qtquickapplication/CMakeLists.txt | 34 ++++++------- .../qtwidgetsapplication/CMakeLists.txt | 49 ++++++++++++++----- src/plugins/android/androidbuildapkstep.cpp | 8 ++- src/plugins/android/androidconstants.h | 1 + .../cmakebuildconfiguration.cpp | 37 +++++++++++--- 5 files changed, 93 insertions(+), 36 deletions(-) diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/CMakeLists.txt b/share/qtcreator/templates/wizards/projects/qtquickapplication/CMakeLists.txt index 3678b3dcdb8..beeae355834 100644 --- a/share/qtcreator/templates/wizards/projects/qtquickapplication/CMakeLists.txt +++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/CMakeLists.txt @@ -11,6 +11,19 @@ set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) +# QtCreator supports the following variables for Android, which are identical to qmake Android variables. +# Check http://doc.qt.io/qt-5/deployment-android.html for more information. +# They need to be set before the find_package(Qt5 ...) call. + +#if(ANDROID) +# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") +# if (ANDROID_ABI STREQUAL "armeabi-v7a") +# set(ANDROID_EXTRA_LIBS +# ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so +# ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so) +# endif() +#endif() + @if %{HasTranslation} find_package(Qt5 COMPONENTS Core Quick LinguistTools REQUIRED) @@ -20,8 +33,7 @@ find_package(Qt5 COMPONENTS Core Quick REQUIRED) @endif if(ANDROID) - set(TARGET %{ProjectName}_${ANDROID_ABI}) - add_library(${TARGET} SHARED + add_library(%{ProjectName} SHARED %{MainCppFileName} qml.qrc @if %{HasTranslation} @@ -29,8 +41,7 @@ if(ANDROID) @endif ) else() - set(TARGET %{ProjectName}) - add_executable(${TARGET} + add_executable(%{ProjectName} %{MainCppFileName} qml.qrc @if %{HasTranslation} @@ -39,22 +50,11 @@ else() ) endif() -target_compile_definitions(${TARGET} +target_compile_definitions(%{ProjectName} PRIVATE $<$,$>:QT_QML_DEBUG>) -target_link_libraries(${TARGET} +target_link_libraries(%{ProjectName} PRIVATE Qt5::Core Qt5::Quick) @if %{HasTranslation} qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES}) @endif - -# QtCreator supports the following variables for Android, which are identical to qmake Android variables. -# Check http://doc.qt.io/qt-5/deployment-android.html for more information. -# These variables must use CACHE, otherwise QtCreator won't see them. - -#if(ANDROID) -# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android" CACHE INTERNAL "") -# if (ANDROID_ABI STREQUAL "armeabi-v7a") -# set(ANDROID_EXTRA_LIBS ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so CACHE INTERNAL "") -# endif() -#endif() diff --git a/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/CMakeLists.txt b/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/CMakeLists.txt index ea825062f41..59f7cf0d65f 100644 --- a/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/CMakeLists.txt +++ b/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/CMakeLists.txt @@ -11,6 +11,19 @@ set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) +# QtCreator supports the following variables for Android, which are identical to qmake Android variables. +# Check http://doc.qt.io/qt-5/deployment-android.html for more information. +# They need to be set before the find_package(Qt5 ...) call. + +#if(ANDROID) +# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") +# if (ANDROID_ABI STREQUAL "armeabi-v7a") +# set(ANDROID_EXTRA_LIBS +# ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so +# ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so) +# endif() +#endif() + @if %{HasTranslation} find_package(Qt5 COMPONENTS Widgets LinguistTools REQUIRED) @@ -19,17 +32,31 @@ set(TS_FILES %{TsFileName}) find_package(Qt5 COMPONENTS Widgets REQUIRED) @endif -add_executable(%{ProjectName} - %{MainFileName} - %{SrcFileName} - %{HdrFileName} -@if %{GenerateForm} - %{FormFileName} -@endif -@if %{HasTranslation} - ${TS_FILES} -@endif -) +if(ANDROID) + add_library(%{ProjectName} SHARED + %{MainFileName} + %{SrcFileName} + %{HdrFileName} + @if %{GenerateForm} + %{FormFileName} + @endif + @if %{HasTranslation} + ${TS_FILES} + @endif + ) +else() + add_executable(%{ProjectName} + %{MainFileName} + %{SrcFileName} + %{HdrFileName} + @if %{GenerateForm} + %{FormFileName} + @endif + @if %{HasTranslation} + ${TS_FILES} + @endif + ) +endif() target_link_libraries(%{ProjectName} PRIVATE Qt5::Widgets) @if %{HasTranslation} diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index bf89bd4a934..ccd9bec14d7 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -393,6 +393,10 @@ void AndroidBuildApkStep::doRun() if (!node) return false; + FilePath deploymentSettingsFile = FilePath::fromString(node->data(Android::Constants::AndroidDeploySettingsFile).toString()); + if (deploymentSettingsFile.exists()) + return true; // cmake creates this file for us + auto targets = node->data(Android::Constants::AndroidTargets).toStringList(); if (targets.isEmpty()) return true; // qmake does this job for us @@ -449,7 +453,7 @@ void AndroidBuildApkStep::doRun() qmlRootPath = target()->project()->rootProjectDirectory().toString(); deploySettings["qml-root-path"] = qmlRootPath; - QFile f{bc->buildDirectory().pathAppended("android_deployment_settings.json").toString()}; + QFile f{deploymentSettingsFile.toString()}; if (!f.open(QIODevice::WriteOnly)) return false; f.write(QJsonDocument{deploySettings}.toJson()); @@ -518,6 +522,8 @@ QVariant AndroidBuildApkStep::data(Core::Id id) const return AndroidConfigurations::currentConfig().bestNdkPlatformMatch(AndroidManager::minimumSDK(target())).mid(8); if (id == Constants::NdkLocation) return QVariant::fromValue(AndroidConfigurations::currentConfig().ndkLocation()); + if (id == Constants::SdkLocation) + return QVariant::fromValue(AndroidConfigurations::currentConfig().sdkLocation()); if (id == Constants::AndroidABIs) return AndroidManager::applicationAbis(target()); diff --git a/src/plugins/android/androidconstants.h b/src/plugins/android/androidconstants.h index b6170877873..8c8f6385556 100644 --- a/src/plugins/android/androidconstants.h +++ b/src/plugins/android/androidconstants.h @@ -82,6 +82,7 @@ const char AndroidManifest[] = "Android.Manifest"; // QStringList const char AndroidNdkPlatform[] = "AndroidNdkPlatform"; //QString const char NdkLocation[] = "NdkLocation"; // FileName +const char SdkLocation[] = "SdkLocation"; // FileName const char AndroidABIs[] = "AndroidABIs"; // QString } // namespace Constants; diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index ba698b9d700..adbf2bc3f8c 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -48,6 +48,7 @@ #include #include +#include #include #include @@ -199,11 +200,13 @@ void CMakeBuildConfiguration::initialize() m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"ANDROID_NDK", CMakeProjectManager::CMakeConfigItem::Type::PATH, "Android NDK PATH", - ndkLocation.toUserOutput().toUtf8()}); + ndkLocation.toString().toUtf8()}); + m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"CMAKE_TOOLCHAIN_FILE", CMakeProjectManager::CMakeConfigItem::Type::PATH, "Android CMake toolchain file", - ndkLocation.pathAppended("build/cmake/android.toolchain.cmake").toUserOutput().toUtf8()}); + ndkLocation.pathAppended("build/cmake/android.toolchain.cmake").toString().toUtf8()}); + auto androidAbis = bs->data(Android::Constants::AndroidABIs).toStringList(); QString preferredAbi; if (androidAbis.contains("arm64-v8a")) { @@ -219,14 +222,23 @@ void CMakeBuildConfiguration::initialize() "Android ABI", preferredAbi.toLatin1(), androidAbis}); + + QtSupport::BaseQtVersion *qt = QtSupport::QtKitAspect::qtVersion(target()->kit()); + if (qt->qtVersion() >= QtSupport::QtVersionNumber{5, 14, 0}) { + auto sdkLocation = bs->data(Android::Constants::SdkLocation).value(); + m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"ANDROID_SDK", + CMakeProjectManager::CMakeConfigItem::Type::PATH, + "Android SDK PATH", + sdkLocation.toString().toUtf8()}); + + } + m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"ANDROID_STL", CMakeProjectManager::CMakeConfigItem::Type::STRING, "Android STL", "c++_shared"}); - m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"CMAKE_FIND_ROOT_PATH_MODE_PROGRAM", "BOTH"}); - m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"CMAKE_FIND_ROOT_PATH_MODE_LIBRARY", "BOTH"}); - m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"CMAKE_FIND_ROOT_PATH_MODE_INCLUDE", "BOTH"}); - m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"CMAKE_FIND_ROOT_PATH_MODE_PACKAGE", "BOTH"}); + + m_initialConfiguration.prepend(CMakeProjectManager::CMakeConfigItem{"CMAKE_FIND_ROOT_PATH", "%{Qt:QT_INSTALL_PREFIX}"}); } BuildStepList *cleanSteps = stepList(ProjectExplorer::Constants::BUILDSTEPS_CLEAN); @@ -434,6 +446,16 @@ void CMakeBuildConfiguration::setConfigurationForCMake(const QList stepLists; + const Core::Id clean = ProjectExplorer::Constants::BUILDSTEPS_CLEAN; + stepLists << stepList(clean); + BuildManager::buildLists(stepLists, QStringList() << ProjectExplorerPlugin::displayNameForStepId(clean)); + } } void CMakeBuildConfiguration::clearError(ForceEnabledChanged fec) @@ -471,7 +493,8 @@ void CMakeBuildConfiguration::setConfigurationForCMake(const CMakeConfig &config { auto configs = removeDuplicates(config); if (m_configurationForCMake.isEmpty()) - m_configurationForCMake = removeDuplicates(configs + m_initialConfiguration); + m_configurationForCMake = removeDuplicates(m_initialConfiguration + + CMakeConfigurationKitAspect::configuration(target()->kit()) + configs); else m_configurationForCMake = configs; From 51991e3a3ee855f12cae999b01a93741c77cf6cd Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Fri, 25 Oct 2019 19:48:48 +0200 Subject: [PATCH 52/57] WebAssembly: fix crashes Change-Id: I9a2a44c85a254628f119eb041036492bc3022cdf Reviewed-by: Alessandro Portale --- .../webassemblyrunconfiguration.cpp | 22 +++++----- .../webassemblyrunconfigurationaspects.cpp | 40 ++++++++++--------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/plugins/webassembly/webassemblyrunconfiguration.cpp b/src/plugins/webassembly/webassemblyrunconfiguration.cpp index 6bed76d2dd0..f4c56630fde 100644 --- a/src/plugins/webassembly/webassemblyrunconfiguration.cpp +++ b/src/plugins/webassembly/webassemblyrunconfiguration.cpp @@ -42,17 +42,19 @@ namespace Internal { static CommandLine emrunCommand(Target *target, const QString &browser, const QString &port) { - BuildConfiguration *bc = target->activeBuildConfiguration(); - const QFileInfo emrunScript = bc->environment().searchInPath("emrun").toFileInfo(); - auto html = bc->buildDirectory().pathAppended(target->project()->displayName() + ".html"); + if (BuildConfiguration *bc = target->activeBuildConfiguration()) { + const QFileInfo emrunScript = bc->environment().searchInPath("emrun").toFileInfo(); + auto html = bc->buildDirectory().pathAppended(target->project()->displayName() + ".html"); - return CommandLine(bc->environment().searchInPath("python"), { - emrunScript.absolutePath() + "/" + emrunScript.baseName() + ".py", - "--browser", browser, - "--port", port, - "--no_emrun_detect", - html.toString() - }); + return CommandLine(bc->environment().searchInPath("python"), { + emrunScript.absolutePath() + "/" + emrunScript.baseName() + ".py", + "--browser", browser, + "--port", port, + "--no_emrun_detect", + html.toString() + }); + } + return {}; } // Runs a webassembly application via emscripten's "emrun" tool diff --git a/src/plugins/webassembly/webassemblyrunconfigurationaspects.cpp b/src/plugins/webassembly/webassemblyrunconfigurationaspects.cpp index aacbc677509..b74d73a5d46 100644 --- a/src/plugins/webassembly/webassemblyrunconfigurationaspects.cpp +++ b/src/plugins/webassembly/webassemblyrunconfigurationaspects.cpp @@ -41,24 +41,26 @@ static QStringList detectedBrowsers(ProjectExplorer::Target *target) { static QStringList result; if (result.isEmpty()) { - const Utils::Environment environment = target->activeBuildConfiguration()->environment(); - const Utils::FilePath emrunPath = environment.searchInPath("emrun"); + if (auto bc = target->activeBuildConfiguration()) { + const Utils::Environment environment = bc->environment(); + const Utils::FilePath emrunPath = environment.searchInPath("emrun"); - QProcess browserLister; - browserLister.setProcessEnvironment(environment.toProcessEnvironment()); - browserLister.setProgram(emrunPath.toString()); - browserLister.setArguments({"--list_browsers"}); - browserLister.start(QIODevice::ReadOnly); + QProcess browserLister; + browserLister.setProcessEnvironment(environment.toProcessEnvironment()); + browserLister.setProgram(emrunPath.toString()); + browserLister.setArguments({"--list_browsers"}); + browserLister.start(QIODevice::ReadOnly); - if (browserLister.waitForFinished()) { - const QByteArray output = browserLister.readAllStandardOutput(); - QTextStream ts(output); - QString line; - const QRegularExpression regExp(" - (.*):.*"); - while (ts.readLineInto(&line)) { - const QRegularExpressionMatch match = regExp.match(line); - if (match.hasMatch()) - result << match.captured(1); + if (browserLister.waitForFinished()) { + const QByteArray output = browserLister.readAllStandardOutput(); + QTextStream ts(output); + QString line; + const QRegularExpression regExp(" - (.*):.*"); + while (ts.readLineInto(&line)) { + const QRegularExpressionMatch match = regExp.match(line); + if (match.hasMatch()) + result << match.captured(1); + } } } } @@ -68,7 +70,8 @@ static QStringList detectedBrowsers(ProjectExplorer::Target *target) WebBrowserSelectionAspect::WebBrowserSelectionAspect(ProjectExplorer::Target *target) : m_availableBrowsers(detectedBrowsers(target)) { - m_currentBrowser = m_availableBrowsers.first(); + if (!m_availableBrowsers.isEmpty()) + m_currentBrowser = m_availableBrowsers.first(); setDisplayName(tr("Web browser")); setId("WebBrowserAspect"); setSettingsKey("RunConfiguration.WebBrowser"); @@ -90,7 +93,8 @@ void WebBrowserSelectionAspect::addToConfigurationLayout(QFormLayout *layout) void WebBrowserSelectionAspect::fromMap(const QVariantMap &map) { - m_currentBrowser = map.value(BROWSER_KEY, m_availableBrowsers.first()).toString(); + if (!m_availableBrowsers.isEmpty()) + m_currentBrowser = map.value(BROWSER_KEY, m_availableBrowsers.first()).toString(); } void WebBrowserSelectionAspect::toMap(QVariantMap &map) const From fea693d9f9434c6396373fa9d97ac92893ad08c5 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 25 Oct 2019 15:09:27 +0200 Subject: [PATCH 53/57] Doc: Update info about enabling the Timeline view in Qt Creator Qt Quick Timeline module is delivered with Qt 5.14 and later. Change-Id: I5666fa0fd190607a1bb6224dcff5ac7f39db61f7 Reviewed-by: Thomas Hartmann --- doc/config/qtcreator-project.qdocconf | 1 + doc/src/qtquick/qtquick-from-qmlproject-to-pro.qdoc | 12 +++++++----- doc/src/qtquick/qtquick-timeline.qdoc | 12 ++++-------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/doc/config/qtcreator-project.qdocconf b/doc/config/qtcreator-project.qdocconf index ba394e3b275..82daf9faad7 100644 --- a/doc/config/qtcreator-project.qdocconf +++ b/doc/config/qtcreator-project.qdocconf @@ -42,6 +42,7 @@ depends += qtwidgets \ qthelp \ qtquickcontrols \ qtquickextras \ + qtquicktimeline \ qtlinguist \ qtscxml \ qtsensors \ diff --git a/doc/src/qtquick/qtquick-from-qmlproject-to-pro.qdoc b/doc/src/qtquick/qtquick-from-qmlproject-to-pro.qdoc index 9e1fe9919ed..ff8d929f9eb 100644 --- a/doc/src/qtquick/qtquick-from-qmlproject-to-pro.qdoc +++ b/doc/src/qtquick/qtquick-from-qmlproject-to-pro.qdoc @@ -64,10 +64,10 @@ Then you can use the \l QQuickView class in the main C++ source file to show the main QML file when the application starts. - At the time of this writing, the Qt Quick Timeline module is delivered with - \QDS, but not with Qt. If you use a timeline in a \QDS project that you - import to \QC, you must build the Qt Quick Timeline module and install it to - your Qt to be able to build your project. + The \l{Qt Quick Timeline} module is delivered with \QDS and with Qt 5.14, + and later. If you use a timeline in a \QDS project that you import to \QC, + and your Qt is older than 5.14, you must build the Qt Quick Timeline module + and install it to your Qt to be able to build your project. \section1 Converting Projects @@ -116,7 +116,9 @@ \section1 Adding Qt Quick Timeline Module to Qt Installations - Check out the Qt Quick Timeline module from + \note You only need to do this if your Qt version is older than 5.14. + + Check out the \l{Qt Quick Timeline} module from \l{https://codereview.qt-project.org/#/admin/projects/qt/qtquicktimeline} {Qt Code Review}. diff --git a/doc/src/qtquick/qtquick-timeline.qdoc b/doc/src/qtquick/qtquick-timeline.qdoc index de012b94e56..b3b40a81675 100644 --- a/doc/src/qtquick/qtquick-timeline.qdoc +++ b/doc/src/qtquick/qtquick-timeline.qdoc @@ -59,14 +59,10 @@ \uicontrol {Qt Quick Designer} > \uicontrol {Enable Timeline editor}. You need to restart \QC for the \uicontrol Timeline view to appear. - To be able to create timelines, you also need the Qt Quick Timeline module. - At the time of this writing, the module is not available as a library in - the Qt installer, and therefore you must check out the repository and build - the module yourself using the same Qt version that you used to build \QC. - - You can check out the module from - \l{https://codereview.qt-project.org/#/admin/projects/qt/qtquicktimeline} - {Qt Code Review Tool}. + To be able to create timelines, you also need the \l {Qt Quick Timeline} + module, which is delivered with Qt 5.14, and later. For more + information about adding the module to an older Qt version, see + \l{Adding Qt Quick Timeline Module to Qt Installations}. \endif \section1 Creating Timelines From 7b2b040f41412c735c67e33d90fdd77cdb7a297f Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 25 Oct 2019 15:47:43 +0200 Subject: [PATCH 54/57] QmlDesigner: Add transaction option to ValuesChangedCommand This option allows to define transactions for ValuesChangedCommand and ValuesModifiedCommand. Change-Id: Ia603027b5c431f1a1912d8959561f92a19fd0243 Reviewed-by: Miikka Heikkinen --- .../commands/valueschangedcommand.cpp | 35 ++++++++++++++----- .../qmlpuppet/commands/valueschangedcommand.h | 7 ++-- .../container/propertyvaluecontainer.cpp | 7 ++++ .../container/propertyvaluecontainer.h | 1 + 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/commands/valueschangedcommand.cpp b/share/qtcreator/qml/qmlpuppet/commands/valueschangedcommand.cpp index c5468bc999b..1ff3bf3320b 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/valueschangedcommand.cpp +++ b/share/qtcreator/qml/qmlpuppet/commands/valueschangedcommand.cpp @@ -95,7 +95,14 @@ QDataStream &operator<<(QDataStream &out, const ValuesChangedCommand &command) { static const bool dontUseSharedMemory = qEnvironmentVariableIsSet("DESIGNER_DONT_USE_SHARED_MEMORY"); - if (!dontUseSharedMemory && command.valueChanges().count() > 5) { + QVector propertyValueContainer = command.valueChanges(); + + if (command.transactionOption != ValuesChangedCommand::TransactionOption::None) { + PropertyValueContainer optionContainer(command.transactionOption); + propertyValueContainer.append(optionContainer); + } + + if (!dontUseSharedMemory && propertyValueContainer.count() > 5) { static quint32 keyCounter = 0; ++keyCounter; command.m_keyNumber = keyCounter; @@ -103,7 +110,7 @@ QDataStream &operator<<(QDataStream &out, const ValuesChangedCommand &command) QDataStream temporaryOutDataStream(&outDataStreamByteArray, QIODevice::WriteOnly); temporaryOutDataStream.setVersion(QDataStream::Qt_4_8); - temporaryOutDataStream << command.valueChanges(); + temporaryOutDataStream << propertyValueContainer; SharedMemory *sharedMemory = createSharedMemory(keyCounter, outDataStreamByteArray.size()); @@ -118,7 +125,7 @@ QDataStream &operator<<(QDataStream &out, const ValuesChangedCommand &command) } out << qint32(0); - out << command.valueChanges(); + out << propertyValueContainer; return out; } @@ -144,17 +151,29 @@ QDataStream &operator>>(QDataStream &in, ValuesChangedCommand &command) { in >> command.m_keyNumber; - if (command.keyNumber() > 0) { - readSharedMemory(command.keyNumber(), &command.m_valueChangeVector); - } else { - in >> command.m_valueChangeVector; + QVector valueChangeVector; + + if (command.keyNumber() > 0) + readSharedMemory(command.keyNumber(), &valueChangeVector); + else + in >> valueChangeVector; + + // '-option-' is not a valid property name and indicates that we store the transaction option. + if (!valueChangeVector.isEmpty() && valueChangeVector.last().name() == "-option-") { + command.transactionOption = + static_cast(valueChangeVector.last().instanceId()); + valueChangeVector.removeLast(); } + + command.m_valueChangeVector = valueChangeVector; + return in; } bool operator ==(const ValuesChangedCommand &first, const ValuesChangedCommand &second) { - return first.m_valueChangeVector == second.m_valueChangeVector; + return first.m_valueChangeVector == second.m_valueChangeVector + && first.transactionOption == second.transactionOption; } QDebug operator <<(QDebug debug, const ValuesChangedCommand &command) diff --git a/share/qtcreator/qml/qmlpuppet/commands/valueschangedcommand.h b/share/qtcreator/qml/qmlpuppet/commands/valueschangedcommand.h index bf7fe1e43d4..5be50903df2 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/valueschangedcommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/valueschangedcommand.h @@ -39,6 +39,7 @@ class ValuesChangedCommand friend bool operator ==(const ValuesChangedCommand &first, const ValuesChangedCommand &second); public: + enum TransactionOption { Start, End, None }; ValuesChangedCommand(); explicit ValuesChangedCommand(const QVector &valueChangeVector); @@ -48,6 +49,7 @@ public: static void removeSharedMemorys(const QVector &keyNumberVector); void sort(); + TransactionOption transactionOption = TransactionOption::None; private: QVector m_valueChangeVector; @@ -69,12 +71,11 @@ QDebug operator <<(QDebug debug, const ValuesChangedCommand &instance); class ValuesModifiedCommand : public ValuesChangedCommand { public: - ValuesModifiedCommand() - {} + ValuesModifiedCommand() = default; + explicit ValuesModifiedCommand(const QVector &valueChangeVector) : ValuesChangedCommand(valueChangeVector) {} - }; } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/container/propertyvaluecontainer.cpp b/share/qtcreator/qml/qmlpuppet/container/propertyvaluecontainer.cpp index cde5957bf5d..19265df0359 100644 --- a/share/qtcreator/qml/qmlpuppet/container/propertyvaluecontainer.cpp +++ b/share/qtcreator/qml/qmlpuppet/container/propertyvaluecontainer.cpp @@ -42,6 +42,13 @@ PropertyValueContainer::PropertyValueContainer(qint32 instanceId, const Property { } +PropertyValueContainer::PropertyValueContainer(qint32 option) + : m_instanceId(option), + m_name("-option-") +{ +// '-option-' is not a valid property name and indicates that we store the transaction option. +} + qint32 PropertyValueContainer::instanceId() const { return m_instanceId; diff --git a/share/qtcreator/qml/qmlpuppet/container/propertyvaluecontainer.h b/share/qtcreator/qml/qmlpuppet/container/propertyvaluecontainer.h index 3423066bc14..4d30f3fb7e4 100644 --- a/share/qtcreator/qml/qmlpuppet/container/propertyvaluecontainer.h +++ b/share/qtcreator/qml/qmlpuppet/container/propertyvaluecontainer.h @@ -43,6 +43,7 @@ class PropertyValueContainer public: PropertyValueContainer(); PropertyValueContainer(qint32 instanceId, const PropertyName &name, const QVariant &value, const TypeName &dynamicTypeName); + PropertyValueContainer(qint32 option); qint32 instanceId() const; PropertyName name() const; From d6b29a89ec980e415cf4c3bdadd32ee850917e05 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 25 Oct 2019 16:09:51 +0200 Subject: [PATCH 55/57] QmlDesigner: Add transactions to NodeInstanceView::valuesModified() Transactions bypass the rewriter and one transaction is one step on the undo/redo stack. Change-Id: Icd782389f74bde2b14432b8f854f29bad49a9104 Reviewed-by: Thomas Hartmann Reviewed-by: Miikka Heikkinen --- .../designercore/include/nodeinstanceview.h | 3 ++ .../instances/nodeinstanceview.cpp | 38 ++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h index 1e1032900bf..5c9356f556e 100644 --- a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h +++ b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h @@ -194,6 +194,8 @@ private: // functions private: void handleCrash(); + void startPuppetTransaction(); + void endPuppetTransaction(); private: //variables NodeInstance m_rootNodeInstance; @@ -209,6 +211,7 @@ private: //variables ProjectExplorer::Kit *m_currentKit = nullptr; ProjectExplorer::Project *m_currentProject = nullptr; int m_restartProcessTimerId; + RewriterTransaction m_puppetTransaction; }; } // namespace ProxyNodeInstanceView diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index ed63caec5ac..92b0880c808 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -70,6 +70,7 @@ #include "nodeinstanceserverproxy.h" #include +#include #include #include @@ -218,6 +219,30 @@ void NodeInstanceView::handleCrash() emitCustomNotification(QStringLiteral("puppet crashed")); } +void NodeInstanceView::startPuppetTransaction() +{ + /* We assume no transaction is active. */ + QTC_ASSERT(!m_puppetTransaction.isValid(), return); + m_puppetTransaction = beginRewriterTransaction("NodeInstanceView::PuppetTransaction"); +} + +void NodeInstanceView::endPuppetTransaction() +{ + /* We assume a transaction is active. */ + QTC_ASSERT(m_puppetTransaction.isValid(), return); + + /* Committing a transaction should not throw, but if there is + * an issue with rewriting we should show an error message, instead + * of simply crashing. + */ + + try { + m_puppetTransaction.commit(); + } catch (Exception &e) { + e.showException(); + } +} + void NodeInstanceView::restartProcess() { if (rootNodeInstance().isValid()) @@ -1195,11 +1220,20 @@ void NodeInstanceView::valuesModified(const ValuesModifiedCommand &command) if (!model()) return; + if (command.transactionOption == ValuesModifiedCommand::TransactionOption::Start) + startPuppetTransaction(); + else if (command.transactionOption == ValuesModifiedCommand::TransactionOption::End) + endPuppetTransaction(); + for (const PropertyValueContainer &container : command.valueChanges()) { if (hasInstanceForId(container.instanceId())) { NodeInstance instance = instanceForId(container.instanceId()); - if (instance.isValid()) - instance.modelNode().variantProperty(container.name()).setValue(container.value()); + if (instance.isValid()) { + ModelNode node = instance.modelNode(); + VariantProperty property = instance.modelNode().variantProperty(container.name()); + if (property.value() != container.value()) + property.setValue(container.value()); + } } } } From 83c6a4d9220dbd1c34ec38b37139471ab279935c Mon Sep 17 00:00:00 2001 From: Denis Shienkov Date: Fri, 25 Oct 2019 12:00:39 +0300 Subject: [PATCH 56/57] BareMetal: Improve IAR parser code a bit It is makes sense to move a handing code of each regexp to the separate method to simplify maintenance. Change-Id: I59d9c23ec1c1c4dabb8de8eb295353b4df072a33 Reviewed-by: Christian Kandeler --- src/plugins/baremetal/iarewparser.cpp | 145 +++++++++++++++----------- src/plugins/baremetal/iarewparser.h | 5 + 2 files changed, 88 insertions(+), 62 deletions(-) diff --git a/src/plugins/baremetal/iarewparser.cpp b/src/plugins/baremetal/iarewparser.cpp index 50e25706ca6..93e97ac056a 100644 --- a/src/plugins/baremetal/iarewparser.cpp +++ b/src/plugins/baremetal/iarewparser.cpp @@ -101,73 +101,96 @@ void IarParser::amendFilePath() m_expectFilePath = false; } +bool IarParser::parseErrorOrFatalErrorDetailsMessage1(const QString &lne) +{ + const QRegularExpression re("^(Error|Fatal error)\\[(.+)\\]:\\s(.+)\\s\\[(.+)$"); + const QRegularExpressionMatch match = re.match(lne); + if (!match.hasMatch()) + return false; + enum CaptureIndex { MessageTypeIndex = 1, MessageCodeIndex, + DescriptionIndex, FilepathBeginIndex }; + const Task::TaskType type = taskType(match.captured(MessageTypeIndex)); + const QString descr = QString("[%1]: %2").arg(match.captured(MessageCodeIndex), + match.captured(DescriptionIndex)); + // This task has a file path, but this patch are split on + // some lines, which will be received later. + const Task task(type, descr, {}, -1, Constants::TASK_CATEGORY_COMPILE); + newTask(task); + // Prepare first part of a file path. + QString firstPart = match.captured(FilepathBeginIndex); + firstPart.remove("referenced from "); + m_filePathParts.push_back(firstPart); + m_expectFilePath = true; + m_expectSnippet = false; + return true; +} + +bool IarParser::parseErrorOrFatalErrorDetailsMessage2(const QString &lne) +{ + const QRegularExpression re("^.*(Error|Fatal error)\\[(.+)\\]:\\s(.+)$"); + const QRegularExpressionMatch match = re.match(lne); + if (!match.hasMatch()) + return false; + enum CaptureIndex { MessageTypeIndex = 1, MessageCodeIndex, + DescriptionIndex }; + const Task::TaskType type = taskType(match.captured(MessageTypeIndex)); + const QString descr = QString("[%1]: %2").arg(match.captured(MessageCodeIndex), + match.captured(DescriptionIndex)); + // This task has not a file path. The description details + // will be received later on the next lines. + const Task task(type, descr, {}, -1, Constants::TASK_CATEGORY_COMPILE); + newTask(task); + m_expectSnippet = true; + m_expectFilePath = false; + m_expectDescription = false; + return true; +} + +bool IarParser::parseWarningOrErrorOrFatalErrorDetailsMessage1(const QString &lne) +{ + const QRegularExpression re("^\"(.+)\",(\\d+)?\\s+(Warning|Error|Fatal error)\\[(.+)\\].+$"); + const QRegularExpressionMatch match = re.match(lne); + if (!match.hasMatch()) + return false; + enum CaptureIndex { FilePathIndex = 1, LineNumberIndex, + MessageTypeIndex, MessageCodeIndex }; + const Utils::FilePath fileName = Utils::FilePath::fromUserInput( + match.captured(FilePathIndex)); + const int lineno = match.captured(LineNumberIndex).toInt(); + const Task::TaskType type = taskType(match.captured(MessageTypeIndex)); + // A full description will be received later on next lines. + const Task task(type, {}, fileName, lineno, Constants::TASK_CATEGORY_COMPILE); + newTask(task); + const QString firstPart = QString("[%1]: ").arg(match.captured(MessageCodeIndex)); + m_descriptionParts.append(firstPart); + m_expectDescription = true; + m_expectSnippet = false; + m_expectFilePath = false; + return true; +} + +bool IarParser::parseErrorInCommandLineMessage(const QString &lne) +{ + if (!lne.startsWith("Error in command line")) + return false; + const Task task(Task::TaskType::Error, lne.trimmed(), {}, + -1, Constants::TASK_CATEGORY_COMPILE); + newTask(task); + return true; +} + void IarParser::stdError(const QString &line) { IOutputParser::stdError(line); const QString lne = rightTrimmed(line); - QRegularExpression re; - QRegularExpressionMatch match; - - re.setPattern("^(Error|Fatal error)\\[(.+)\\]:\\s(.+)\\s\\[(.+)$"); - match = re.match(lne); - if (match.hasMatch()) { - enum CaptureIndex { MessageTypeIndex = 1, MessageCodeIndex, - DescriptionIndex, FilepathBeginIndex }; - const Task::TaskType type = taskType(match.captured(MessageTypeIndex)); - const QString descr = QString("[%1]: %2").arg(match.captured(MessageCodeIndex), - match.captured(DescriptionIndex)); - // This task has a file path, but this patch are split on - // some lines, which will be received later. - const Task task(type, descr, {}, -1, Constants::TASK_CATEGORY_COMPILE); - newTask(task); - // Prepare first part of a file path. - QString firstPart = match.captured(FilepathBeginIndex); - firstPart.remove("referenced from "); - m_filePathParts.push_back(firstPart); - m_expectFilePath = true; - m_expectSnippet = false; + if (parseErrorOrFatalErrorDetailsMessage1(lne)) return; - } - - re.setPattern("^.*(Error|Fatal error)\\[(.+)\\]:\\s(.+)$"); - match = re.match(lne); - if (match.hasMatch()) { - enum CaptureIndex { MessageTypeIndex = 1, MessageCodeIndex, - DescriptionIndex }; - const Task::TaskType type = taskType(match.captured(MessageTypeIndex)); - const QString descr = QString("[%1]: %2").arg(match.captured(MessageCodeIndex), - match.captured(DescriptionIndex)); - // This task has not a file path. The description details - // will be received later on the next lines. - const Task task(type, descr, {}, -1, Constants::TASK_CATEGORY_COMPILE); - newTask(task); - m_expectSnippet = true; - m_expectFilePath = false; - m_expectDescription = false; + if (parseErrorOrFatalErrorDetailsMessage2(lne)) return; - } - - re.setPattern("^\"(.+)\",(\\d+)?\\s+(Warning|Error|Fatal error)\\[(.+)\\].+$"); - match = re.match(lne); - if (match.hasMatch()) { - enum CaptureIndex { FilePathIndex = 1, LineNumberIndex, - MessageTypeIndex, MessageCodeIndex }; - const Utils::FilePath fileName = Utils::FilePath::fromUserInput( - match.captured(FilePathIndex)); - const int lineno = match.captured(LineNumberIndex).toInt(); - const Task::TaskType type = taskType(match.captured(MessageTypeIndex)); - // A full description will be received later on next lines. - const Task task(type, {}, fileName, lineno, Constants::TASK_CATEGORY_COMPILE); - newTask(task); - const QString firstPart = QString("[%1]: ").arg(match.captured(MessageCodeIndex)); - m_descriptionParts.append(firstPart); - m_expectDescription = true; - m_expectSnippet = false; - m_expectFilePath = false; + if (parseWarningOrErrorOrFatalErrorDetailsMessage1(lne)) return; - } if (lne.isEmpty()) { // @@ -201,12 +224,10 @@ void IarParser::stdOutput(const QString &line) IOutputParser::stdOutput(line); const QString lne = rightTrimmed(line); - if (!lne.startsWith("Error in command line")) + + if (!parseErrorInCommandLineMessage(lne)) return; - const Task task(Task::TaskType::Error, line.trimmed(), {}, - -1, Constants::TASK_CATEGORY_COMPILE); - newTask(task); doFlush(); } diff --git a/src/plugins/baremetal/iarewparser.h b/src/plugins/baremetal/iarewparser.h index 48348d4f6fa..d3fc2d1454f 100644 --- a/src/plugins/baremetal/iarewparser.h +++ b/src/plugins/baremetal/iarewparser.h @@ -46,6 +46,11 @@ private: void amendDescription(); void amendFilePath(); + bool parseErrorOrFatalErrorDetailsMessage1(const QString &lne); + bool parseErrorOrFatalErrorDetailsMessage2(const QString &lne); + bool parseWarningOrErrorOrFatalErrorDetailsMessage1(const QString &lne); + bool parseErrorInCommandLineMessage(const QString &lne); + void stdError(const QString &line) final; void stdOutput(const QString &line) final; void doFlush() final; From 0a7b9db9b43fc1647a7d7f277c6bebafa9115e5b Mon Sep 17 00:00:00 2001 From: Denis Shienkov Date: Fri, 25 Oct 2019 12:20:38 +0300 Subject: [PATCH 57/57] BareMetal: Handle missed stdout error generated by IAR linker Change-Id: I767363697dc56d9314ff6c34605a907807975864 Reviewed-by: Christian Kandeler --- src/plugins/baremetal/iarewparser.cpp | 33 ++++++++++++++++++++++++++- src/plugins/baremetal/iarewparser.h | 1 + 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/plugins/baremetal/iarewparser.cpp b/src/plugins/baremetal/iarewparser.cpp index 93e97ac056a..039e32aa8d8 100644 --- a/src/plugins/baremetal/iarewparser.cpp +++ b/src/plugins/baremetal/iarewparser.cpp @@ -179,6 +179,22 @@ bool IarParser::parseErrorInCommandLineMessage(const QString &lne) return true; } +bool IarParser::parseErrorMessage1(const QString &lne) +{ + const QRegularExpression re("^(Error)\\[(.+)\\]:\\s(.+)$"); + const QRegularExpressionMatch match = re.match(lne); + if (!match.hasMatch()) + return false; + enum CaptureIndex { MessageTypeIndex = 1, MessageCodeIndex, DescriptionIndex }; + const Task::TaskType type = taskType(match.captured(MessageTypeIndex)); + const QString descr = QString("[%1]: %2").arg(match.captured(MessageCodeIndex), + match.captured(DescriptionIndex)); + // This task has not a file path and line number (as it is a linker message) + const Task task(type, descr, {}, -1, Constants::TASK_CATEGORY_COMPILE); + newTask(task); + return true; +} + void IarParser::stdError(const QString &line) { IOutputParser::stdError(line); @@ -225,7 +241,10 @@ void IarParser::stdOutput(const QString &line) const QString lne = rightTrimmed(line); - if (!parseErrorInCommandLineMessage(lne)) + // The call sequence has the meaning! + const bool leastOneParsed = parseErrorInCommandLineMessage(lne) + || parseErrorMessage1(lne); + if (!leastOneParsed) return; doFlush(); @@ -297,6 +316,18 @@ void BareMetalPlugin::testIarOutputParsers_data() categoryCompile)) << QString(); + QTest::newRow("Linker error") + << QString::fromLatin1("Error[e46]: Some error") + << OutputParserTester::STDOUT + << QString::fromLatin1("Error[e46]: Some error\n") + << QString() + << (Tasks() << Task(Task::Error, + QLatin1String("[e46]: Some error"), + Utils::FilePath(), + -1, + categoryCompile)) + << QString(); + // For std error. QTest::newRow("No details warning") << QString::fromLatin1("\"c:\\foo\\main.c\",63 Warning[Pe223]:\n" diff --git a/src/plugins/baremetal/iarewparser.h b/src/plugins/baremetal/iarewparser.h index d3fc2d1454f..28cd89960ff 100644 --- a/src/plugins/baremetal/iarewparser.h +++ b/src/plugins/baremetal/iarewparser.h @@ -50,6 +50,7 @@ private: bool parseErrorOrFatalErrorDetailsMessage2(const QString &lne); bool parseWarningOrErrorOrFatalErrorDetailsMessage1(const QString &lne); bool parseErrorInCommandLineMessage(const QString &lne); + bool parseErrorMessage1(const QString &lne); void stdError(const QString &line) final; void stdOutput(const QString &line) final;